import mpi4py.rc
mpi4py.rc.initialize = False
from mpi4py import MPI
import logging
import numpy as np
from copy import deepcopy
from PyNucleus_base.myTypes import REAL
from PyNucleus_base.utilsFem import TimerManager, updateFromDefaults
from PyNucleus_fem.boundaryLayerCy import boundaryLayer
from PyNucleus_fem.algebraicOverlaps import multilevelAlgebraicOverlapManager
from . levels import meshLevel, algebraicLevel
from . levels import (DELETE_MESH, KEEP_MESH,
                      SPARSITY_PATTERN, DOFMAPS,
                      NO_BUILD, RESTRICTION_PROLONGATION_ONLY,
                      SPARSITY_ONLY, SINGLE_LEVEL, FULL_BUILD)

LOGGER = logging.getLogger(__name__)

class EmptyHierarchy(object):
    def __init__(self, params, label=''):
        self.params = params
        self.updateParamsFromDefaults()
        self.label = label
        self.connectorEnd = None

    def isSetUp(self):
        return False

    def updateParamsFromDefaults(self):
        defaults = {}
        updateFromDefaults(self.params, defaults)

class hierarchy:
    def __init__(self, meshLevel, params, comm=None,
                 label=''):
        self._isSetUp = False
        self.connectorStart = None
        self.connectorEnd = None
        self.params = params
        self.updateParamsFromDefaults(self.params)
        self.comm = comm
        self.label = label

        self.Timer = TimerManager(LOGGER, comm=self.comm, prefix=self.label+': ')

        if self.params['keepMeshes'] == 'all':
            self.meshInformationPolicy = [KEEP_MESH]*self.params['noRef'] + [KEEP_MESH]
        elif self.params['keepMeshes'] == 'last':
            self.meshInformationPolicy = [DELETE_MESH]*self.params['noRef'] + [KEEP_MESH]
        elif self.params['keepMeshes'] == 'none':
            self.meshInformationPolicy = [DELETE_MESH]*self.params['noRef'] + [DELETE_MESH]
        else:
            raise NotImplementedError(self.params['keepMeshes'])

        if self.params['assemble'] == 'all':
            if self.params['meshTransformation'] is None:
                self.buildType = [SPARSITY_ONLY]*self.params['noRef'] + [FULL_BUILD]
            else:
                self.buildType = [FULL_BUILD]*self.params['noRef'] + [FULL_BUILD]
        elif self.params['assemble'] == 'ALL':
            self.buildType = [FULL_BUILD]*self.params['noRef'] + [FULL_BUILD]
        elif self.params['assemble'] == 'last':
            self.buildType = [RESTRICTION_PROLONGATION_ONLY]*self.params['noRef'] + [FULL_BUILD]
        elif self.params['assemble'] == 'first+last':
            self.buildType = [FULL_BUILD]+[RESTRICTION_PROLONGATION_ONLY]*(self.params['noRef']-1) + [FULL_BUILD]
        elif self.params['assemble'] == 'dofmaps only':
            self.buildType = [DOFMAPS]*(self.params['noRef']+1)
        elif self.params['assemble'] == 'none':
            self.buildType = [NO_BUILD]*(self.params['noRef']+1)
        elif self.params['assemble'] == 'restrictionProlongation':
            self.buildType = [RESTRICTION_PROLONGATION_ONLY]*(self.params['noRef']+1)
        elif self.params['assemble'] == 'dofmap only last':
            self.buildType = [NO_BUILD]*self.params['noRef']+[DOFMAPS]
        else:
            raise NotImplementedError()

        if 'buildInteriorBL' in params and params['buildInteriorBL']:
            meshLevel.interiorBL = boundaryLayer(meshLevel.mesh, params['depth']+1,
                                                 afterRefinements=params['noRef'])

        if meshLevel is not None:
            self.meshLevels = [meshLevel]
            self.algebraicLevels = [self.meshLevels[-1].getAlgebraicLevel(self.buildType[0])]
        else:
            self.meshLevels = []
            self.algebraicLevels = []
        self.multilevelAlgebraicOverlapManager = None

    @staticmethod
    def updateParamsFromDefaults(params):
        defaults = {
            'keepMeshes': 'last',
            'assemble': 'all',
            'depth': 0,
            'noRef': 0,
            'buildInteriorBL': False,
            'debugOverlaps': False,
            'meshTransformation': None,
            'diffusivity': None,
            'reaction': None,
            'symmetric': False,
            'reorder': False,
            'buildMass': False,
            'element': 'P1',
            'commType': 'standard',
            'keepAllDoFMaps': False,
            'interiorBC': 'homogeneousNeumann',
            'buildSurfaceMass': False,
            'buildSurfaceStiffness': False,
            'overlapMatvec': False,
            'meshTransformation': None,
            'debugOverlaps': False
        }
        updateFromDefaults(params, defaults)

    def refine(self, isLastLevel=False):
        # refine mesh level
        meshInformationPolicy = self.meshInformationPolicy[self.meshLevels[-1].levelNo+1-self.meshLevels[0].levelNo]
        self.meshLevels.append(self.meshLevels[-1].refine(meshInformationPolicy))
        self.meshLevels[-1].isLastLevel = isLastLevel

        # build algebraic level
        buildType = self.buildType[self.meshLevels[-1].levelNo-self.meshLevels[0].levelNo]
        self.algebraicLevels.append(self.meshLevels[-1].getAlgebraicLevel(buildType))

        # clean up unneeded data
        if len(self.meshLevels) > 1:
            self.meshLevels[-2].clean()
            self.algebraicLevels[-2].clean()

    def build(self):
        for k in range(self.params['noRef']):
            self.refine(k == self.params['noRef']-1)
        self.algebraicLevels[-1].buildCoarserMatrices()

        if self.algebraicLevels[-1].algebraicOverlaps is not None:
            with self.Timer("Build multilevel overlaps"):
                if False:
                   raise NotImplementedError()
                else:
                    multLvlAlgOvManager = multilevelAlgebraicOverlapManager(self.comm)
                    for lvl in range(len(self.algebraicLevels)):
                        multLvlAlgOvManager.levels.append(self.algebraicLevels[lvl].algebraicOverlaps)
                        if self.buildType[lvl] & DOFMAPS:
                            multLvlAlgOvManager.levels[lvl].prepareDistribute()

                    if self.params['debugOverlaps']:
                        from PyNucleus_fem import solSin1D, solSin2D, solSin3D
                        for lvl in range(len(self.algebraicLevels)):
                            if self.algebraicLevels[lvl].DoFMap is not None:
                                dm = self.algebraicLevels[lvl].DoFMap
                                if self.meshLevels[-1].mesh.dim == 1:
                                    x = dm.interpolate(solSin1D)
                                elif self.meshLevels[-1].mesh.dim == 2:
                                    x = dm.interpolate(solSin2D)
                                elif self.meshLevels[-1].mesh.dim == 3:
                                    x = dm.interpolate(solSin3D)
                                else:
                                    raise NotImplementedError()
                                y = np.zeros((dm.num_dofs), dtype=REAL)
                                y[:] = x
                                multLvlAlgOvManager.levels[lvl].distribute_py(y)
                                multLvlAlgOvManager.levels[lvl].accumulate_py(y)
                                assert np.linalg.norm(x-y) < 1e-9, (x, y)
                self.multilevelAlgebraicOverlapManager = multLvlAlgOvManager
        self._isSetUp = True

    def isSetUp(self):
        return self._isSetUp

    def getLevelList(self, recurse=True):
        if self.connectorStart is not None and recurse:
            levels = self.connectorStart.getLevelList()
        else:
            levels = []
        levelsMesh = [mL.getLevelDict() for mL in self.meshLevels]
        levelsAlg = [aL.getLevelDict() for aL in self.algebraicLevels]
        for i in range(len(levelsAlg)):
            levelsAlg[i].update(levelsMesh[i])
        levelsAlg = levels[:-1]+levelsAlg

        if self.multilevelAlgebraicOverlapManager is not None:
            levelsAlg[-1]['multilevelAlgebraicOverlapManager'] = self.multilevelAlgebraicOverlapManager
        return levelsAlg

    @staticmethod
    def fromLevelList(levels, params={}, comm=None, label=''):
        hierarchy.updateParamsFromDefaults(params)
        params['assemble'] = 'none'
        meshLevels = []
        prevMeshLevel = None
        algebraicLevels = []
        for lvl in levels:
            meshLevels.append(meshLevel.fromLevelDict(lvl, params=params, previousLevel=prevMeshLevel, comm=comm, label=label))
            prevMeshLevel = meshLevels[-1]
            algebraicLevels.append(algebraicLevel.fromLevelDict(prevMeshLevel, lvl))
        h = hierarchy(meshLevels[0], params, comm=comm)
        h.meshLevels = meshLevels
        h.algebraicLevels = algebraicLevels
        h._isSetUp = True
        return h

    def buildCollapsedRestrictionProlongation(self):
        self.P = self.algebraicLevels[1].P
        for lvlNo in range(2, len(self.algebraicLevels)):
            self.P = self.algebraicLevels[lvlNo].P*self.P
        self.P = self.P.to_csr_linear_operator()
        self.R = self.P.transpose()

    def gatherInformation(self, root=0):
        import platform

        subdomain = self.meshLevels[-1].mesh
        A = self.algebraicLevels[-1].A
        overlaps = self.multilevelAlgebraicOverlapManager
        info = {}
        info['numberVertices'] = self.comm.gather(subdomain.num_vertices, root=root)
        info['numberCells'] = self.comm.gather(subdomain.num_cells, root=root)
        info['numberDoFs'] = self.comm.gather(A.shape[0], root=root)
        if self.comm.size > 1:
            info['globalNumDoFs'] = overlaps.countDoFs()
            info['numberSharedDoFs'] = self.comm.gather(overlaps.get_num_shared_dofs(unique=False), root=root)
            info['maxCross'] = overlaps.levels[-1].max_cross
            neighbors = [subdomainNo for subdomainNo in overlaps.levels[-1].overlaps]
        else:
            info['globalNumDoFs'] = A.shape[0]
            info['numberSharedDoFs'] = [0]
            info['maxCross'] = [0]
            neighbors = []
        info['nnz'] = self.comm.gather(A.nnz, root=root)
        hostname = platform.node()
        info['hostnames'] = self.comm.gather(hostname, root=root)
        info['neighbors'] = self.comm.gather(neighbors, root=root)
        info['rank'] = self.comm.gather(MPI.COMM_WORLD.rank, root=root)
        return info

    def __len__(self):
        return len(self.meshLevels)

    def getSubHierarchy(self, numLevels):
        assert 0 <= numLevels < len(self)

        h = hierarchy(None, self.params, self.comm, self.label)
        h.connectorStart = self.connectorStart
        h.connectorEnd = self.connectorEnd
        h.meshLevels = self.meshLevels[:numLevels+1]
        h.algebraicLevels = self.algebraicLevels[:numLevels+1]
        h.multilevelAlgebraicOverlapManager = self.multilevelAlgebraicOverlapManager
        return h

class pCoarsenHierarchy(hierarchy):
    def __init__(self, meshLevel, params, comm=None,
                 label=''):
        assert params['noRef']+1 == len(params['element']), 'Number of refinements does not match number of provided DoFMaps: {}+1 != len({})'.format(params['noRef'], params['element'])
        self.elements = params['element']
        params['element'] = self.elements[0]
        super(pCoarsenHierarchy, self).__init__(meshLevel, params, comm, label)

    def refine(self, isLastLevel=False):
        # refine mesh level
        self.meshLevels.append(self.meshLevels[-1].copy())
        self.meshLevels[-1].isLastLevel = isLastLevel
        self.meshLevels[-1].params['element'] = self.elements[len(self.meshLevels)-1]

        # build algebraic level
        buildType = self.buildType[self.meshLevels[-1].levelNo-self.meshLevels[0].levelNo]
        self.algebraicLevels.append(self.meshLevels[-1].getAlgebraicLevel(buildType))

        # clean up unneeded data
        if len(self.meshLevels) > 1:
            self.meshLevels[-2].clean()
            self.algebraicLevels[-2].clean()

class hierarchyManager(object):
    def __init__(self, hierarchyDefs, connectorDefs, params, comm=None, doDeepCopy=True):
        if doDeepCopy:
            self.hierarchies = deepcopy(hierarchyDefs)
            self.connectors = deepcopy(connectorDefs)
        else:
            self.hierarchies = hierarchyDefs
            self.connectors = connectorDefs
        self.params = params
        if comm is None:
            from PyNucleus_base.utilsCy import FakeComm
            comm = FakeComm(0, 1)
        self.comm = comm
        for h in self.hierarchies:
            updateFromDefaults(h['params'], self.params)
        self._printRank = -1

    def getPrintRank(self):
        if self._printRank == -1:
            self._printRank = self.comm.allreduce(self.comm.rank if not isinstance(self.builtHierarchies[-1], EmptyHierarchy) else self.comm.size, op=MPI.MIN)
        return self._printRank

    def setCommunicators(self):
        for k in range(len(self.hierarchies)):
            h = self.hierarchies[k]
            if k == 0 or h['ranks'] != self.hierarchies[k-1]:
                if (self.comm is not None) and (len(h['ranks']) < self.comm.size):
                    if self.comm.rank in h['ranks']:
                        h['comm'] = self.comm.Split(0)
                    else:
                        self.comm.Split(MPI.UNDEFINED)
                        h['comm'] = None
                else:
                    h['comm'] = self.comm
            else:
                h['comm'] = self.hierarchies[k-1]['comm']
            if h['connectorEnd'] is not None:
                self.connectors[h['connectorEnd']]['comm1'] = h['comm']
            if h['connectorStart'] is not None:
                self.connectors[h['connectorStart']]['comm2'] = h['comm']
            if k == 0 and h['connectorStart'] is not None and len(h['ranks']) > 1:
                self.connectors[h['connectorStart']]['comm1'] = h['comm']

        for conn in sorted(self.connectors):
            c = self.connectors[conn]
            if 'comm1' in c:
                if c['comm1'] is not None or c['comm2'] is not None:
                    c['global_comm'] = self.comm.Split(0)
                else:
                    self.comm.Split(MPI.UNDEFINED)
                    c['global_comm'] = None
            else:
                c['comm1'] = None
                c['global_comm'] = c['comm2']

    def buildHierarchies(self):
        builtHierarchies = []
        builtConnectors = {}
        currentHierarchy = None
        for k in range(len(self.hierarchies)):
            h = self.hierarchies[k]
            c_params = self.connectors[h['connectorStart']]
            self.comm.Barrier()
            if c_params['global_comm'] is not None:
                connector = c_params['type'](c_params['global_comm'], c_params['comm1'], c_params['comm2'], currentHierarchy, **c_params['params'])
                currentHierarchy = connector.getNewHierarchy(h)
                builtConnectors[h['connectorStart']] = connector
                builtHierarchies.append(currentHierarchy)
            else:
                currentHierarchy = EmptyHierarchy(h['params'], label=h['label'])
                builtHierarchies.append(currentHierarchy)
            if c_params['global_comm'] is not None:
                connector.build()
            if h['comm'] is not None:
                currentHierarchy.build()
        self.builtHierarchies = builtHierarchies
        self.builtConnectors = builtConnectors

    def setup(self):
        self.setCommunicators()
        self.buildHierarchies()

    def display(self, info=False):
        msg = []
        if self.comm.rank == 0:
            msg.append('{:30} {}'.format('', ' '.join([str(i) for i in range(self.comm.size)])))
        h = self.hierarchies[0]
        if h['connectorStart'] is not None:
            conn = h['connectorStart']
            t = self.comm.gather(self.connectors[conn]['global_comm'] is not None)
            if self.comm.rank == 0:
                msg.append('{:30} {}'.format(conn, ' '.join(["-" if tt else " " for tt in t])))
        for k, h in enumerate(self.hierarchies):
            t = self.comm.gather(h['comm'] is not None, root=min(h['ranks']))
            if self.comm.rank == min(h['ranks']):
                msg2 = []
                for j in range(len(self.builtHierarchies[k].meshLevels)):
                    l = self.builtHierarchies[k].meshLevels[j]
                    msg2.append('{:30} {}'.format(l.levelID, ' '.join(["o" if tt else " " for tt in t])))
                    if info:
                        algLevel = self.builtHierarchies[k].algebraicLevels[j]
                        msg2[-1] += '  '
                        keys = algLevel.getKeys()
                        msg2[-1] += ' '.join(key for key in keys if getattr(algLevel, key) is not None)
                msg2 = '\n'.join(msg2)
                self.comm.send(msg2, dest=0, tag=7767)
            if self.comm.rank == 0:
                s2 = self.comm.recv(source=min(h['ranks']), tag=7767)
                msg.append(s2)
            if h['connectorEnd'] is not None:
                conn = h['connectorEnd']
                if self.connectors[conn]['comm1'] is not None and self.connectors[conn]['comm2'] is None:
                    # symbol = '┴'
                    symbol = '-'
                elif self.connectors[conn]['comm1'] is not None and self.connectors[conn]['comm2'] is not None:
                    # symbol = '┼'
                    symbol = '-'
                elif self.connectors[conn]['comm1'] is None and self.connectors[conn]['comm2'] is not None:
                    # symbol = '┬'
                    symbol = '-'
                else:
                    symbol = ' '
                t = self.comm.gather(symbol)
                if self.comm.rank == 0:
                    s = t[0]
                    for i in range(1, len(t)):
                        if t[i-1] != ' ' and t[i] != ' ':
                            # s += '─' + t[i]
                            s += '-' + t[i]
                        else:
                            s += ' ' + t[i]
                    msg.append('{:30} {}'.format(conn, s))
        if self.comm.rank == 0:
            LOGGER.info('\n' + '\n'.join(msg))

    def getLevelList(self):
        k = len(self.builtHierarchies)-1
        while self.builtHierarchies[k] is None:
            k -= 1
        return self.builtHierarchies[k].getLevelList()

    @staticmethod
    def fromLevelList(levels, params={}, comm=None):
        # TODO: Assumes single rank so far
        if comm is None:
            comm = MPI.COMM_SELF
            comm = None
        hierarchyDefs = [{'label': 'fine',
                          'ranks': set([0]),
                          'connectorStart': None,
                          'connectorEnd': None,
                          'params': {'solver': 'LU'}}]
        connectorDefs = {}
        hM = hierarchyManager(hierarchyDefs, connectorDefs, params, comm)
        hM.setCommunicators()
        hM.builtHierarchies = [hierarchy.fromLevelList(levels, params=hierarchyDefs[0]['params'], comm=comm, label=hierarchyDefs[0]['label'])]
        hM.builtConnectors = {}
        return hM

    def getComm(self):
        k = len(self.builtHierarchies)-1
        while self.builtHierarchies[k] is None:
            k -= 1
        return self.builtHierarchies[k].comm

    def hierarchyIsSetUp(self, label):
        for h in self.builtHierarchies:
            if h is not None and h.label == label:
                return h.isSetUp()
        return False

    def getHierarchy(self, label):
        for h in self.builtHierarchies:
            if h is not None and h.label == label:
                return h
        return None

    def __getitem__(self, label):
        return self.getHierarchy(label)

    def getSubManager(self, label=None):
        if label is not None:
            for k, h in enumerate(self.builtHierarchies):
                if h is not None and h.label == label:
                    subManager = hierarchyManager(self.hierarchies[:k+1], self.connectors, self.params, self.comm, doDeepCopy=False)
                    subManager.builtHierarchies = self.builtHierarchies[:k+1]
                    subManager.builtConnectors = self.builtConnectors
                    return subManager
            raise Exception()
        else:
            k = len(self.hierarchies)-2
            subManager = hierarchyManager(self.hierarchies[:k+1], self.connectors, self.params, self.comm, doDeepCopy=False)
            subManager.builtHierarchies = self.builtHierarchies[:k+1]
            subManager.builtConnectors = self.builtConnectors
            return subManager

    def collectInformation(self, hierarchies, root=-1):
        if root == -1:
            root = self.getPrintRank()
        info = {}
        tag = 263
        req = []
        for label in hierarchies:
            if not isinstance(self[label], EmptyHierarchy):
                i = self[label].gatherInformation(root=0)
                if self[label].comm.rank == 0:
                    req.append(self.comm.isend(i, dest=root, tag=tag))
            if self.comm.rank == root:
                info[label] = self.comm.recv(source=MPI.ANY_SOURCE, tag=tag)
            tag += 1
        MPI.Request.Waitall(req)
        return info

    def getSubHierarchy(self, numFineLevels):
        hM = hierarchyManager(self.hierarchies, self.connectors, self.params, self.comm, doDeepCopy=False)
        hM.builtHierarchies = self.builtHierarchies[:-1]
        hM.builtConnectors = self.builtConnectors
        h = self.builtHierarchies[-1].getSubHierarchy(numFineLevels)
        hM.builtHierarchies.append(h)

        return hM


''' interface
class Forder:
    def __init__(self, name):
        self.name = name
        self.children = {}

    def add_child(self, child):
        pass

    def move(self, new_path): #common method
        pass

    def delete(self):#common method
        pass

class File:
    def __init__(self, name, contents):
        self.name = name
        self.contents = contents

    def move(self, new_path): #common method
        pass

    def delete(self):#common method
        pass
'''
#-------------------------------------------------------
class Component:
    def __init__(self, name):
        self.name = name

    def move(self, new_path):
        new_folder = get_path(new_path)
        del(self.parent.children[self.name])
        new_folder.children[self.name] = self
        self.parent = new_folder

    def delete(self):
        #delete from the parent the child with the current name
        del(self.parent.children[self.name])

class Folder(Component):
    def __init__(self, name):
        self.name = name
        self.children = {}

    def add_child(self, child):
        child.parent = self
        self.children[child.name] = child

class File(Component):
    def __init__(self, name, contents):
        self.name = name
        self.contents = contents

root = Folder('')
def get_path(path):
    names = path.split('/')[1:]
    node = root
    for name in names:
        node = node.children[name]
    return node

if __name__=='__main__':
    folder1 = Folder('folder1')
    folder2 = Folder('folder2')

    root.add_child(folder1)
    root.add_child(folder2)

    folder11 = Folder('folder11')
    folder1.add_child(folder11)

    file111 = File('file111', 'contents')
    folder11.add_child(file111)

    file21 = File('file21', 'other contents')
    folder2.add_child(file21)

    print(root.children)
    print(folder2.children)


from django.shortcuts import render
from teams.models import clubs, players

# Create your views here.

def viewClubs(request):
	clubs_list = []
	clubs_obj = clubs.objects.all()

	for club1 in clubs_obj:
		clubs_dict = {}

		clubs_dict['name'] = club1.name
		clubs_dict['nickname'] = club1.nickname
		clubs_dict['stadium'] = club1.stadium
		clubs_dict['manager'] = club1.manager

		clubs_list.append(clubs_dict)

		return render(request, 'clubs.html', {'clubs_list': clubs_list})

def viewPlayers(request):
	players_list = []
	players_obj = players.objects.all()

	for players1 in players_obj:
		players_dict = {}

		players_dict['name'] = players1.name
		players_dict['club'] = players1.club
		players_dict['position'] = players1.position
		players_dict['born'] = players1.born
		players_dict['nationality'] = players1.nationality

		players_list.append(players_dict)

	return render(request, 'players.html', {'players_list': players_list})


import astropy.io.votable.treeFits as vo
from scipy import misc
import numpy as np
import os

# nm = glob.glob('/home/johann/Desktop/*.png')[0]
# imArr = misc.imread(nm).astype(np.int32)
# r, c = imArr.shape
# print imArr.dtype

votable = vo.VOTableFile(version='1.3')

resource = vo.Resource()

votable.resources.append(resource)

table = vo.Table(votable)
resource.tables.append(table)
table.description = 'Lette A from non-MNIST set'

table.format = 'fits'

fits_path = "./A_fits.fits"
if( os.path.exists(fits_path)):
  table.set_href('file://' + os.path.abspath(fits_path))

votable.to_xml('A_vo_fits.xml')


from fastapi import FastAPI

app = FastAPI()
stu_data=[{'name':'vetri',"age":23,'id':1},{"name":"pravin","age":22,'id':2},
          {
              'id':3,'age':23,'name':'david'
          }]

@app.get("/")
async def root():
    return {"message": "Hello World"}
# get by id
@app.get('/getbyid/{id}')
async def getById(id:int):
    if id!=0:
        return stu_data[id-1]
    else:
        return 'not id found'
# get by name
@app.get('/getbyname/{name}')
async def getName(name:str):
  for i in stu_data:
      if i['name']==name:
          return i
  return 'not found data'

# get by ID
@app.post('/add')
async def addbyid(id:int,age:int,name:str):
    stu_data.append({'id':id,'name':name,'age':age})
    return stu_data
@app.put('/edit/{id}')
async def edit(id:int,name:str,age:int):
    s =stu_data[id-1]
    s['name']=name
    s['age']=age
    return s

# delete by id
@app.delete('/delete')
async def  delete(id:int):
    deleted_stu=stu_data.pop(id-1)
    return {'deleted id':id,'delede data':deleted_stu}


"""
第五章 基于数组的序列

"""

# %% 5-1 List-length and cache-size
import sys
def list_size_test(n=10):
    data=[]
    for k in range(n):
        a=len(data)
        b=sys.getsizeof(data)
        print('Length:%d; Size in bytes:%d'%(a,b))
        data.append(None)
# %% 5-3 Implement DynamicArray using ctypes-method
import ctypes
class DynamicArray:
    """ A dynamic array class akin to Python-list"""
    def __init__(self):
        """ Create an empty array"""
        self._n=0           # 动态数组长度
        self._capacity=1    # 动态数组容量
        self._A=self._make_array(self._capacity)
    def __len__(self):
        """ Return numbers of elements in array"""
        return self._n
    def __getitem__(self, item):
        """ Return element at index item"""
        if not 0<=item<self._n:
            raise IndexError('Found # Invalid Index')
        return self._A[item]
    def __str__(self):
        """ To show this data-struct"""
        return 'd'+str(self._A[:self._n-1])+'d'
    def append(self,obj):
        """ Add object to the end of array"""
        if self._n==self._capacity:
            self._resize(2*self._capacity)
        self._A[self._n]=obj
        self._n+=1
    # 5-5 添加元素方法
    def insert(self, k, value):
        """ 在索引k处插入值value"""
        if self._n==self._capacity:  # 若空间不足,扩充
            self._resize(2*self._capacity)
        for i in range(self._n, k, -1):
            self._A[i] = self._A[i-1]
        self._A[k]=value
        self._n+=1
    # 5-6 删除元素方法
    def remove(self,value):
        """ 删除值为value的第一次出现的元素"""
        for i in range(self._n):
            if self._A[i] == value:
                for j in range(i,self._n-1):
                    self._A[j] = self._A[j+1]
                self._n-=1
                return
        raise ValueError(' Announced Value not found.')
    def _resize(self,c):
        """ 为数组动态扩增提供支持 Resize the internal array"""
        B=self._make_array(c)
        for i in range(self._n):
            B[i]=self._A[i]
        self._A=B
        self._capacity=c
    # @staticmethod   # 静态方法无需实例化类即可在外部调用
    def _make_array(self, c):
        """ 调用ctypes模块创建底层数组 Return new array with capacity-c"""
        return (c*ctypes.py_object)()
# %% 5-4 测量列表类增添操作的摊销花费
from time import time
def compute_average_amortization_time(n):
    """ 计算向列表中加入n个元素时的平均摊销时间花费
        结果得到：每个append的摊销时间独立于n"""
    temp=[]
    time_start=time()
    for i in range(n):
        temp.append(None)
    time_end=time()
    return (time_end-time_start)/n
# %% 5-7 GameEntry类用于存储玩家姓名和得分
class GamePlayer:
    """ 表示对每个玩家的信息记录"""
    def __init__(self,name,score):
        self._name = name
        self._score = score
    def get_name(self):
        return self._name
    def get_score(self):
        return self._score
    def __str__(self):
        return '[{0}:{1}]'.format(self._name,self._score)
# %% 5-8 Scoreboard类 用于实现计分榜功能
class Scoreboard:
    """ 将高分更新至容量有限的计分榜上"""
    def __init__(self, capacity=6):
        self._board = [None]*capacity   # 保留计分空间
        self._n = 0     # 计分榜上已有记录的个数
    def __getitem__(self, item):
        """ 返回索引为item处的元素"""
        return self._board[item]
    def __str__(self):
        """ 返回计分榜的字符串表示"""
        return '\n'.join(str(self._board[i]) for i in range(self._n))
    def add(self,entry):
        """ 尝试添加一个元素到计分榜上"""
        score=entry.get_score()
        if self._n<len(self._board) or self._board[-1].get_score()<=score:
            # 计分榜未满 或 新分数大于等于榜上最小值
            if self._n<len(self._board):
                self._n+=1  # 先扩充一个
            j=self._n-1
            while j>0 and self._board[j-1].get_score()<score:
                self._board[j] = self._board[j-1]
                j-=1
            self._board[j]=entry
# %% 5-10 Insertion_sort 插入排序算法
def insertion_sort(A):
    """ 将列表元素按非减顺序排列"""
    for i in range(1,len(A)):
        cur=A[i]
        j=i
        while j>0 and A[j-1]>cur:
            A[j] = A[j-1]
            j-=1
        A[j]=cur
# %% 5-11 CaesarCipher 凯撒密码加密解密
class CassarCipher:
    """ 用于将字符串通过凯撒密码加密或解密"""
    def __init__(self,shift=2):
        """ 建立凯撒密码的整数编号替换表"""
        encoder = [None]*26
        decoder = [None]*26
        for i in range(26):
            encoder[i] = chr((i+shift)%26 + ord('A'))
            decoder[i] = chr((i-shift)%26 + ord('A'))
        self._encode_table = ''.join(encoder)
        self._decode_table = ''.join(decoder)
    def encrypt(self, message):
        """ 返回加密后的字符串"""
        return self._transform(message, self._encode_table)
    def decrypt(self, message):
        """ 返回解密后的字符串"""
        return self._transform(message, self._decode_table)
    def _transform(self, original_msg, code):
        """ 根据所给的编码加密或解密"""
        msg = list(original_msg)
        for i in range(len(original_msg)):
            if msg[i].isupper():
                j=ord(msg[i])-ord('A')
                msg[i]=code[j]
        return ''.join(msg)
# %% 5-12 TicTacToe 三连棋
class TicTacToe:
    """ 井字棋的类实现"""
    def __init__(self):
        """  开始游戏 初始化棋盘"""
        self._board=[[' ']*3 for i in range(3)]
        self._player='X'
        print('井字棋游戏开始，请输入TicTacToe.mark(i,j)表示下棋位置')
    def mark(self,i,j):
        """ 放置X或O到(i,j)位置"""
        if not(0<=i<=2 and 0<=j<=2):
            raise ValueError('Invalid board position')
        if self._board[i][j] != ' ':
            raise ValueError('Board position occupied')
        if self.winner() is not None:
            raise ValueError('Game is already done!')
        self._board[i][j] = self._player
        print(self.__str__())
        print(self.winner())
        if self._player=='X':
            self._player='O'
        else:self._player='X'
    def _is_win(self,mark):
        """ 检查该步是否会得出赢家"""
        board = self._board
        return (mark == board[0][0] == board[0][1] == board[0][2] or
                mark == board[1][0] == board[1][1] == board[1][2] or
                mark == board[2][0] == board[2][1] == board[2][2] or
                mark == board[0][0] == board[1][0] == board[2][0] or
                mark == board[0][1] == board[1][1] == board[2][1] or
                mark == board[0][2] == board[1][2] == board[2][2] or
                mark == board[0][0] == board[1][1] == board[2][2] or
                mark == board[0][2] == board[1][1] == board[2][0])
    def winner(self):
        """ 返回胜利玩家标号 或None表示平局"""
        for mark in 'XO':
            if self._is_win(mark):
                return 'Winner is '+mark
        return 'Game unfinished'
    def __str__(self):
        """ 返回字符串表示当前棋盘"""
        rows=['|'.join(self._board[i]) for i in range(3)]
        return '\n-----\n'.join(rows)

# %% test
if __name__=='__main__':
    a = DynamicArray()
    a._make_array(102400000)
    sys.getsizeof(a)
    # 5-11
    cipher1=CassarCipher(2)
    message='THIS IS NOT A BIG DEAL!'
    encode_msg=cipher1.encrypt(message)
    print('encode_msg:',encode_msg,'\ndecode_msg:',cipher1.decrypt(encode_msg))
    # 5-12
    game=TicTacToe()
    game.mark(1,1)
    game.mark(2,0)
    game.mark(2,2)
    game.mark(0,0)
    game.mark(1,2)
    game.mark(1,0)
    game.mark(0,1)


#!/usr/bin/env python
# coding: utf-8

# # Predicting using supervised ML
#
# In this section we will see how python Scikit Learn library is used to predict the percentage of an student based on the number of study hours
# (This is simple Linear Regression task as it involves only 2 variables)
#
# Author Name:Huda kouli
#

# In[30]:

#importing required libraries
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error
from sklearn.metrics import median_absolute_error

# In[31]:

#Reading data set and X,y
dataset = pd.read_csv('Data.csv')
print(dataset.head(10))
X = dataset.iloc[:,:1]
y = dataset.iloc[:, -1]

# In[32]:

#spliting data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)

# In[33]:

#Training Model
regressor = LinearRegression()
regressor.fit(X_train, y_train)

# In[34]:

regressor.score(X_train, y_train)

# In[35]:

regressor.score(X_test, y_test)

# In[36]:

#Testing model
y_pred = regressor.predict(X_test)
y_pred

# In[37]:

#printing y_test to compare the actual output with the predicted values
y_test

# In[38]:

#printing predicted score for one value (hours)
y_pred_new=regressor.predict([[9.25]])
y_pred_new

# In[39]:

mean_absolute_error(y_test, y_pred)

# In[40]:

mean_squared_error(y_test, y_pred)

# In[41]:

median_absolute_error(y_test, y_pred)

# In[42]:

# Visualising the Training,testing sets results
plt.scatter(X_train, y_train, color = 'red')
plt.scatter(X_test, y_test, color = 'green')
plt.plot(X_train, regressor.predict(X_train), color = 'blue')
plt.title('Score for student')
plt.xlabel('Hours')
plt.ylabel('Score')
plt.show()

# In[ ]:

# In[ ]:


import tensorflow as tf

import numpy as np

import utils
import word_utils

# import matplotlib.pyplot as plt
import os

os.environ['TF_CPP_MIN_LOG_LEVEL']='2'

' Code for learning tensorflow '

__author__ = 'Wenwu Yang'

#tensorboard --logdir="./graphs" --port 6006; http://localhost:6006/

DATA_FILE = 'data/birth_life_2010.txt'

def read_birth_life_data(filename):
	with open(filename, 'r') as fp:
		text = fp.readlines()[1:]

	data = [ line[:-1].split('\t')  for line in text ]
	data = [ (float(line[1]), float(line[2])) for line in data ]
	n_sample = len(data)
	data = np.asarray(data, dtype = np.float32)

	return data, n_sample

# Step 1: read in the data
data, n_sample = read_birth_life_data(DATA_FILE)

# Use the huber loss
def huber_loss(labels, predictions, delta=14.0):
    residual = tf.abs(labels - predictions)
    def f1(): return 0.5 * tf.square(residual)
    def f2(): return delta * residual - 0.5 * tf.square(delta)
    return tf.cond(residual < delta, f1, f2)

def use_placeholder_for_data():
	# Step 2: assemble the graph for linear regression neural net
	# Y = wX + b
	X = tf.placeholder(tf.float32, name = 'X')
	Y = tf.placeholder(tf.float32, name = 'Y')

	w = tf.get_variable('weights', initializer=tf.constant(0.0))
	b = tf.get_variable('bias', initializer=tf.constant(.0))

	Y_predicted = w*X + b

	loss2 = huber_loss(Y, Y_predicted)
	optimizer2 = tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(loss2)

	with tf.Session() as sess:
		sess.run(tf.global_variables_initializer())

		for i in range(100): # 100 epochs
			total_loss = 0
			for x, y in data:
				_, l = sess.run([optimizer2, loss2], feed_dict={X:x, Y:y})
				total_loss += l

			print('Epoch {0}: {1}'.format(i, total_loss/n_sample))

		w_out2, b_out2 = sess.run([w, b])

	# Evaluate the results
	print('w, b: (%f, %f)\n'%(w_out2, b_out2))

	# plot the results
	plt.plot( data[:,0], data[:, 1], 'bo', label='Real data' )
	# plt.plot( data[:,0], data[:,0]*w_out+b_out, 'r', label='Predicted data:square_loss'  )
	plt.plot( data[:,0], data[:,0]*w_out2+b_out2, 'g', label='Predicted data:huber_loss'  )
	plt.legend()
	plt.show()

# # Y = wX^2 + uX + b
# X = tf.placeholder(tf.float32, name = 'X')
# Y = tf.placeholder(tf.float32, name = 'Y')

# w = tf.get_variable('weights_w', initializer=tf.constant(0.0))
# u = tf.get_variable('weights_u', initializer=tf.constant(0.0))
# b = tf.get_variable('weights', initializer=tf.constant(0.0))

# Y_predicted = w*X*X + u*X + b

# loss = tf.square(Y - Y_predicted, name = 'loss')

# optimizer = tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(loss)

# # Step3: run the session
# writer = tf.summary.FileWriter('./graphs', tf.get_default_graph())
# with tf.Session() as sess:
# 	sess.run(tf.global_variables_initializer())

# 	for i in range(100): # 100 epochs
# 		total_loss = 0
# 		for x, y in data:
# 			_, l = sess.run([optimizer, loss], feed_dict={X:x, Y:y})
# 			total_loss += l

# 		print('Epoch {0}: {1}'.format(i, total_loss/n_sample))

# 	writer.close()

# 	w_out, b_out = sess.run([w, b])

# # Evaluate the results
# print('w, b: (%f, %f)\n'%(w_out, b_out))

def use_tfdata_for_data():
	dataset = tf.data.Dataset.from_tensor_slices((data[:,0], data[:,1]))
	print(dataset.output_types)
	print(dataset.output_shapes)

	# iterator = dataset.make_one_shot_iterator()
	iterator = dataset.make_initializable_iterator()
	X, Y = iterator.get_next()

	w = tf.get_variable('weights', initializer=tf.constant(0.0))
	b = tf.get_variable('bias', initializer=tf.constant(.0))

	Y_predicted = w*X + b

	loss2 = huber_loss(Y, Y_predicted)
	optimizer2 = tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(loss2)

	with tf.Session() as sess:
		sess.run(tf.global_variables_initializer())

		for i in range(100):
			sess.run(iterator.initializer)
			total_loss = .0
			try:
				while True:
					_, l = sess.run([optimizer2, loss2])
					total_loss += l
			except tf.errors.OutOfRangeError:
				pass

			print('Epoch {0}: {1}'.format(i, total_loss/n_sample))

		w_out2, b_out2 = sess.run([w, b])

	# Evaluate the results
	print('w, b: (%f, %f)\n'%(w_out2, b_out2))

def logistic_regression_mnist():
	# Define paramaters for the model
	learning_rate = 0.01
	batch_size = 128
	n_epochs = 30
	n_train = 60000
	n_test = 10000

	# prepare the data
	mnist_folder = 'data/mnist'
	utils.download_mnist(mnist_folder)
	train, val, test = utils.read_mnist(mnist_folder, flatten=True)

	print('{0}, {1}'.format(n_test, len(test[0])))
	print(test)
	assert n_test == len(test[0]), 'Number of testing dataset is wrong!'

	train_data = tf.data.Dataset.from_tensor_slices(train)
	train_data = train_data.shuffle(10000)
	test_data = tf.data.Dataset.from_tensor_slices(test)

	train_data = train_data.batch(batch_size)
	test_data = test_data.batch(batch_size)

	iterator = tf.data.Iterator.from_structure(train_data.output_types, train_data.output_shapes)
	img, label = iterator.get_next()
	train_init = iterator.make_initializer(train_data)
	test_init = iterator.make_initializer(test_data)

	# Construct the optimization pipeline

	# Step 1: create weights and bias
	# w is initialized to random variables with mean of 0, stddev of 0.01
	# b is initialized to 0
	# shape of w depends on the dimension of X and Y so that Y = tf.matmul(X, w)
	# shape of b depends on Y
	# X corresponds to an image with size of (28, 28) which is flattened to have the dimension of (1, 784)
	# Y is a vector containg 10 digits
	w = tf.get_variable(name='weights', shape=(784, 10), initializer=tf.random_normal_initializer(0, 0.01))
	b = tf.get_variable(name='bias', shape=(1, 10), initializer=tf.zeros_initializer())

	# Step 2: build model
	# the model that returns the logits.
	# this logits will be later passed through softmax layer
	logits = tf.matmul(img, w) + b

	# Step 3: define loss function
	# use cross entropy of softmax of logits as the loss function
	entropy = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=label, name='entropy')
	loss = tf.reduce_mean(entropy, name='loss') # computes the mean over all the examples in the batch

	# Step 4: define training op
	# using gradient descent with learning rate of 0.01 to minimize loss
	optimizer = tf.train.AdamOptimizer(learning_rate).minimize(loss)

	# Step 5: calculate accuracy with test set
	preds = tf.nn.softmax(logits)
	correct_preds = tf.equal(tf.argmax(preds, 1), tf.argmax(label, 1))
	accuracy = tf.reduce_sum(tf.cast(correct_preds, tf.float32))

	writer = tf.summary.FileWriter('./graphs/logreg', tf.get_default_graph())

	# run the optimization
	with tf.Session() as sess:
		sess.run( tf.global_variables_initializer() )

		for i in range(n_epochs):
			sess.run(train_init)
			total_loss = 0
			n_batches = 0
			try:
				while True:
					_, l = sess.run([optimizer, loss])
					total_loss += l
					n_batches += 1
			except tf.errors.OutOfRangeError:
				pass
			print('Avrage loss epoch {0}: {1}'.format(i, total_loss/n_batches))

		# test the model
		sess.run(test_init)
		total_correct_preds = 0
		try:
			while True:
				accuracy_batch = sess.run(accuracy)
				total_correct_preds += accuracy_batch
		except tf.errors.OutOfRangeError:
			pass

		print('Accuracy {0}'.format(total_correct_preds/n_test))

	writer.close()

def tensorflow_dataslice_format():
	data = np.zeros( (3, 4, 5) )
	data2 = np.ones((3,))
	dataset = tf.data.Dataset.from_tensor_slices((data, data2))
	iterator = dataset.make_one_shot_iterator()
	value1, value2 = iterator.get_next()

	"""
	In tensorflow or numpy, the data is arranged in list[] format, and the tuple (),
	is just used to zip/combine the data. Note: tuple does not correspond to a data, which
	is different from the tuple in python.
	"""

	with tf.Session() as sess:
		no = 1
		try:
			while True:
				x, y = sess.run([value1, value2])
				print("Data {0}: {1}, {2}".format(no, x, y))
				no += 1
		except tf.errors.OutOfRangeError:
			pass

def tensorflow_common_ops():
# Simple exercies to get used to tensorflow API

###############################################################################
# 1a: Create two random 0-d tensors x and y of any distribution.
# Create a TensorFlow object that returns x + y if x > y, and x - y otherwise.
# Hint: look up tf.cond()
# I do the first problem for you
###############################################################################
	# # tf.set_random_seed(10) # one seed corresponds to a randomness generator
	# x = tf.random_uniform([], seed = 5)
	# y = tf.random_uniform([])
	# v = tf.cond(x>y, lambda: x+y, lambda: x-y) # only function format is provided not including its params
	# with tf.Session() as sess:
	# 	xx, yy, vv = sess.run([x, y, v])
	# 	print("x:{0}; y:{1}; z:{2}".format(xx, yy, vv))

###############################################################################
# 1b: Create two 0-d tensors x and y randomly selected from the range [-1, 1).
# Return x + y if x < y, x - y if x > y, 0 otherwise.
# Hint: Look up tf.case().
###############################################################################
	# tf.set_random_seed(10)
	# x = tf.random_uniform([])
	# y = tf.random_uniform([])
	# v = tf.case({x<y:lambda:x+y, x>y:lambda:x-y}, default=lambda:tf.constant(.0), exclusive=True)
	# # ops in tensorflow should be tensor, py number cannot be used directly.
	# with tf.Session() as sess:
	# 	xx, yy, vv = sess.run((x, y, v))
	# 	print("x:{0}; y:{1}; v:{2}".format(xx, yy, vv))

###############################################################################
# 1c: Create the tensor x of the value [[0, -2, -1], [0, 1, 2]]
# and y as a tensor of zeros with the same shape as x.
# Return a boolean tensor that yields Trues if x equals y element-wise.
# Hint: Look up tf.equal().
###############################################################################
	# x = tf.constant([ [0,-2,-1], [0,1,2] ])
	# y = tf.zeros_like(x)
	# v = tf.equal(x, y)
	# with tf.Session() as sess:
	# 	xx, yy, vv = sess.run((x, y, v))
	# 	print("x:{0}; y:{1}; v:{2}".format(xx, yy, vv))

###############################################################################
# 1d: Create the tensor x of value
# [29.05088806,  27.61298943,  31.19073486,  29.35532951,
#  30.97266006,  26.67541885,  38.08450317,  20.74983215,
#  34.94445419,  34.45999146,  29.06485367,  36.01657104,
#  27.88236427,  20.56035233,  30.20379066,  29.51215172,
#  33.71149445,  28.59134293,  36.05556488,  28.66994858].
# Get the indices of elements in x whose values are greater than 30.
# Hint: Use tf.where().
# Then extract elements whose values are greater than 30.
# Hint: Use tf.gather().
###############################################################################
	data = [29.05088806,  27.61298943,  31.19073486,  29.35532951,
			30.97266006,  26.67541885,  38.08450317,  20.74983215,
			34.94445419,  34.45999146,  29.06485367,  36.01657104,
			27.88236427,  20.56035233,  30.20379066,  29.51215172,
			33.71149445,  28.59134293,  36.05556488,  28.66994858]
	x = tf.constant(data)
	y = tf.constant(30, shape=np.shape(data), dtype=tf.float32)
	# Parameters of the tensorflow ops should not be tensor unless the param corresponds to a tensor data
	pos = tf.where(x > y)
	q = tf.gather(x, pos)
	with tf.Session() as sess:
		xx, yy, pp, qq = sess.run((x, y, pos, q))
		print("x:{0}; y:{1}; pos:{2}; q:{3}".format(xx, yy, pp, qq.flatten()))

def word_2_vec():
	# Model hyperparameters
	VOCAB_SIZE = 50000
	BATCH_SIZE = 128
	EMBED_SIZE = 128            # dimension of the word embedding vectors
	SKIP_WINDOW = 1             # the context window
	NUM_SAMPLED = 64            # number of negative examples to sample
	LEARNING_RATE = 1.0
	NUM_TRAIN_STEPS = 100000
	VISUAL_FLD = 'visualization'
	SKIP_STEP = 5000

	# Parameters for downloading data
	DOWNLOAD_URL = 'http://mattmahoney.net/dc/text8.zip'
	EXPECTED_BYTES = 31344016
	NUM_VISUALIZE = 3000        # number of tokens to visualize

	# Prepare the dataset
	# gen = word_utils.batch_gen(DOWNLOAD_URL, EXPECTED_BYTES, VOCAB_SIZE, BATCH_SIZE, SKIP_WINDOW, VISUAL_FLD)

	# for i in range(2):
	# 	print('epoch:{0}'.format(i))
	# 	center_words, target_words = next(gen)
	# 	print(center_words)

	def gen() : yield from word_utils.batch_gen(DOWNLOAD_URL, EXPECTED_BYTES, VOCAB_SIZE, BATCH_SIZE, SKIP_WINDOW, VISUAL_FLD)

	dataset = tf.data.Dataset.from_generator(gen, (tf.int32, tf.int32), (tf.TensorShape([BATCH_SIZE]), tf.TensorShape([BATCH_SIZE, 1])))

	# Build the graph for word2vec model
	# Step 1: get input, output from the dataset
	with tf.name_scope('data'):
		iterator = dataset.make_initializable_iterator()
		center_words, target_words = iterator.get_next()

	""" Step 2+3: define weights and embedding lookup
	In word2vec, it's actually the weights that we care about
	"""
	with tf.name_scope('embed'):
		embed_matrix = tf.get_variable('embed_matrix',
		          shape = [VOCAB_SIZE, EMBED_SIZE],
		          initializer=tf.random_uniform_initializer())
		embed = tf.nn.embedding_lookup(embed_matrix, center_words, name = 'embedding')

	# step 4: construct variable for NCE loss and define the loss function
	with tf.name_scope('loss'):
		nce_weights = tf.get_variable('nce_weight', shape=[VOCAB_SIZE, EMBED_SIZE])
		nce_bias = tf.get_variable('nce_bias', initializer=tf.zeros([VOCAB_SIZE]))

		# define loss function to be NCE loss function
		loss = tf.reduce_mean(tf.nn.nce_loss( weights = nce_weights,
		                       biases = nce_bias,
							   labels=target_words,
							   inputs=embed,
							   num_sampled=NUM_SAMPLED,
							   num_classes=VOCAB_SIZE, name = 'loss') )

	# Step 5: define optimizer
	with tf.name_scope('optimizer'):
		optimizer = tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(loss)

	utils.safe_mkdir('checkpoints')

	with tf.Session() as sess:
		sess.run(iterator.initializer)
		sess.run(tf.global_variables_initializer())

		total_loss = .0 # we use this to calculate late average loss in the last skip_step step
		writer = tf.summary.FileWriter('graphs/word2vec_simple', sess.graph)

		for index in range(NUM_TRAIN_STEPS):
			try:
				loss_batch, _ = sess.run([loss, optimizer])
				total_loss += loss_batch
				if(index+1)%SKIP_STEP == 0:
					print('Average loss at step {0}:{1:5.1f}'.format(index+1, total_loss/SKIP_STEP))
					total_loss = .0
			except tf.errors.OutOfRangeError:
				sess.run(iterator.initializer) # Re-start the batch generator. Note that the gen function would be run from the starting once again

		writer.close()

if __name__ == '__main__':
	# use_placeholder_for_data()
	# use_tfdata_for_data()
	# logistic_regression_mnist()
	# tensorflow_dataslice_format()
	# tensorflow_common_ops()
	word_2_vec()
	tf.truncated_normal()
	x1 = tf.truncated_normal([200, 100], name='x1')


def bigger_price(limit: int, data: list) -> list:
    price_dict = {}
    for i in data:
        if i["price"] not in price_dict:
            price_dict[i["price"]] = []
            price_dict[i["price"]].append(i["name"])
        else:
            price_dict[i["price"]].append(i["name"])

    list_of_price = sorted(price_dict.keys(), reverse=True)

    return_list = []
    for price in list_of_price:
        if len(price_dict[price]) > 1:
            for i in range(0, len(price_dict[price])):
                return_list.append({"name": price_dict[price][i], "price": price})
        else:
            return_list.append({"name": price_dict[price][0], "price": price})

    return return_list[0:limit]

if __name__ == '__main__':
    from pprint import pprint
    print('Example:')
    print(bigger_price(2, [
        {"name": "bread", "price": 100},
        {"name": "wine", "price": 138},
        {"name": "meat", "price": 15},
        {"name": "water", "price": 1},
        {"name": "juice", "price": 15}

    ]))

    # These "asserts" using for self-checking and not for auto-testing
    assert bigger_price(2, [
        {"name": "bread", "price": 100},
        {"name": "wine", "price": 138},
        {"name": "meat", "price": 15},
        {"name": "water", "price": 1}
    ]) == [
        {"name": "wine", "price": 138},
        {"name": "bread", "price": 100}
    ]

    assert bigger_price(1, [
        {"name": "pen", "price": 5},
        {"name": "whiteboard", "price": 170}
    ]) == [{"name": "whiteboard", "price": 170}]

    print('Done! Looks like it is fine. Go and check it')


import subprocess

republicans  = open('data/r.txt', 'r')
rList = republicans.readlines()
rCommands = open('rCommands.txt', 'w')
democrats  = open('data/d.txt', 'r')
dList = democrats.readlines()
dCommands = open('dCommands.txt', 'w')

for i in range(len(rList)):
    rList[i] = rList[i][:-1]
    name_of_file = 'data/r/' + rList[i] + '.csv'
    rCommands.write('twitterscraper -u ' + rList[i] + ' -l 500 -c -o ' + name_of_file + '\n')

for i in range(len(dList)):
    dList[i] = dList[i][:-1]
    name_of_file = 'data/d/' + dList[i] + '.csv'
    dCommands.write('twitterscraper -u ' + dList[i] + ' -l 500 -c -o ' + name_of_file + '\n')


from __future__ import annotations

from promptware.constants import (
    ApplicationCategory,
    ApplicationSubcategory,
    DesignPatternType,
    LanguageType,
    LicenseType,
    PlatformType,
    TaskType,
)
from promptware.info import SoftwareInfo
from promptware.kernels.plm import PLMKernelConfig
from promptware.promptware import PromptConfig, Promptware

conversation_friend = PromptConfig(
    name="conversation_friend",
    description="Emulate a text message conversation.",
    instruction="",
    demonstration=[
        "You: What have you been up to?\n"
        "Friend: Watching old movies.\n"
        "You: Did you watch anything interesting?\n"
        "Friend: Yes, I watched The Omen and Troy.",
    ],
    prompt_template=lambda input: f"You: {input['text']}\nFriend:",
    task=TaskType.qa_open_domain,
)

class ConversationPromptware(Promptware):
    def _info(self) -> SoftwareInfo:
        return SoftwareInfo(
            description="Open ended conversation with an AI assistant.",
            creator="OpenAI",
            homepage="https://beta.openai.com/examples/",
            reference="",
            codebase_url="https://beta.openai.com/examples/",
            license=LicenseType.no_license,
            research_tasks=[TaskType.qa_open_domain],
            application_categories=[ApplicationCategory.conversation],
            application_subcategories=[ApplicationSubcategory.open_ended_conversation],
            original_platform=PlatformType.gpt3,
            design_pattern=DesignPatternType.standalone,
            source_language=LanguageType.en,
            target_language=LanguageType.en,
        )

    def _kernel_configs(self):
        return {
            "openai2": PLMKernelConfig(
                platform="openai",
                model_name="text-curie-001",
                max_tokens=60,
                temperature=0.5,
                top_p=1,
                frequency_penalty=0.5,
                presence_penalty=0,
            ),
        }

    def execute(self, input):

        openai_kernel2 = self.kernel_configs["openai2"].to_kernel()
        code = self.get_code(input, self.software_configs["conversation_friend"])
        return self.normalize_output(openai_kernel2.execute(code)["text"])

    def _software_configs(self):
        return {"conversation_friend": conversation_friend}

    def _example(self):
        return {
            "input": {"text": "I'd like to cancel my subscription."},
            "output": "No problem!",
        }


import enum
import pygame
import os
import typing

import lib.globals
import lib.replay
import lib.scene.replay
import lib.scene.result
import lib.sound
import lib.sprite
import lib.stg_overlay
import lib.utils

class Opcode(enum.IntEnum):
    NOOP = enum.auto()
    DEBUGGER = enum.auto()
    HALT = enum.auto()
    WAIT = enum.auto()

    JUMP = enum.auto()
    JUMP_E = enum.auto()
    JUMP_NE = enum.auto()
    JUMP_L = enum.auto()
    JUMP_LE = enum.auto()
    JUMP_G = enum.auto()
    JUMP_GE = enum.auto()
    JUMP_BOSS = enum.auto()
    JUMP_NOBOSS = enum.auto()

    STORE = enum.auto()
    RANDOM_INT = enum.auto()
    RANDOM_FLOAT = enum.auto()
    INC = enum.auto()
    DEC = enum.auto()
    ADD = enum.auto()
    SUB = enum.auto()
    MUL = enum.auto()
    DIV = enum.auto()
    MOD = enum.auto()
    FDIV = enum.auto()

    SET_SCROLL_SPEED = enum.auto()
    SET_MASK_ALPHA = enum.auto()
    SET_MASK_SPEED = enum.auto()
    LOAD_STAGE = enum.auto()
    SPAWN = enum.auto()
    BGM = enum.auto()
    BOSS_WARNING = enum.auto()
    SET_CLEARED = enum.auto()
    DISABLE_CONTINUE = enum.auto()
    SHOW_RESULT = enum.auto()

    # = enum.auto()

enemyScriptCache: dict[str, str] = {}

class Engine:
    @staticmethod
    def parseLine(line: str) -> tuple[tuple[Opcode, list[typing.Union[int, float, str]]], typing.Optional[str]]:
        params = line.split()
        if not params:
            return (None, None)
        opcode = params.pop(0)
        if opcode == '#':
            return (None, None)
        opcode = Opcode[opcode]

        for index, value in enumerate(params):
            if value == '#':
                return ((opcode, params[:index]), None)
            elif value == '@':
                return ((opcode, params[:index]), params[index + 1])
            try:
                params[index] = int(value)
            except ValueError:
                try:
                    params[index] = float(value)
                except ValueError:
                    pass
        return ((opcode, params), None)

    @staticmethod
    def parseScript(script: str) -> typing.Sequence[tuple[Opcode, typing.Sequence[typing.Union[int, float, str]]]]:
        result: list[tuple[Opcode, list[typing.Union[int, float, str]]]] = []
        lineTags: dict[str, int] = {}
        lineCounter = 0
        for line in script.splitlines():
            parsed, tag = Engine.parseLine(line)
            if tag:
                lineTags[tag] = lineCounter
            if parsed:
                result.append(parsed)
                lineCounter += 1
        for i, r in enumerate(result):
            for j, p in enumerate(r[1]):
                if isinstance(p, str) and p[0] == '@':
                    r[1][j] = lineTags[p[1:]] - i
        # for r in result:
        #     print(r)
        return result

    def __init__(self, script: str) -> None:
        self.instruction = Engine.parseScript(script)
        self.pointer = 0
        self.wait = 0
        self.halted = False
        self.vars: list[typing.Union[int, float, str]] = list(None for x in range(8))

    def applyParamsReplacement(self, params: typing.Sequence[typing.Union[int, float, str]]) -> None:
        result = []
        for value in params:
            isVar = False
            if isinstance(value, str) and value.startswith('%VAR_'):
                for i in range(8):
                    if value == f'%VAR_{i}%':
                        result.append(self.vars[i])
                        isVar = True
                        break
            if not isVar:
                if value == '%PLAYER_X%':
                    result.append(lib.globals.groupPlayer.sprite.position.x)
                elif value == '%PLAYER_Y%':
                    result.append(lib.globals.groupPlayer.sprite.position.y)
                elif value == '%CONTINUE_COUNT%':
                    result.append(lib.globals.continueCount)
                else:
                    result.append(value)
        return result

    def update(self):
        if self.wait > 0:
            self.wait -= 1

        while not self.halted and not self.wait:
            opcode, params = self.instruction[self.pointer]
            params = self.applyParamsReplacement(params)
            # print(opcode, params, self.vars)
            self.pointer += 1
            self.executeOpcode(opcode, params)

    def executeOpcode(self, opcode: Opcode, params: typing.Sequence[typing.Union[int, float, str]]):
        if opcode == Opcode.NOOP:
            pass
        elif opcode == Opcode.DEBUGGER:
            print('Debugger triggered from line', self.pointer, 'at frame', self.context.frameCounter)
        elif opcode == Opcode.WAIT:
            params: tuple[int] = params
            waitTime, = params

            self.wait = waitTime
        elif opcode == Opcode.HALT:
            self.halted = True
        elif opcode == Opcode.JUMP:
            params: tuple[int] = params
            offset, = params

            self.pointer += offset - 1
        elif opcode == Opcode.JUMP_E:
            params: tuple[typing.Union[int, float], typing.Union[int, float], int] = params
            a, b, offset = params

            if a == b:
                self.pointer += offset - 1
        elif opcode == Opcode.JUMP_NE:
            params: tuple[typing.Union[int, float], typing.Union[int, float], int] = params
            a, b, offset = params

            if a != b:
                self.pointer += offset - 1
        elif opcode == Opcode.JUMP_L:
            params: tuple[typing.Union[int, float], typing.Union[int, float], int] = params
            a, b, offset = params

            if a < b:
                self.pointer += offset - 1
        elif opcode == Opcode.JUMP_LE:
            params: tuple[typing.Union[int, float], typing.Union[int, float], int] = params
            a, b, offset = params

            if a <= b:
                self.pointer += offset - 1
        elif opcode == Opcode.JUMP_G:
            params: tuple[typing.Union[int, float], typing.Union[int, float], int] = params
            a, b, offset = params

            if a > b:
                self.pointer += offset - 1
        elif opcode == Opcode.JUMP_GE:
            params: tuple[typing.Union[int, float], typing.Union[int, float], int] = params
            a, b, offset = params

            if a >= b:
                self.pointer += offset - 1
        elif opcode == Opcode.JUMP_BOSS:
            params: tuple[int] = params
            offset, = params

            if lib.globals.groupBoss.sprite:
                self.pointer += offset - 1
        elif opcode == Opcode.JUMP_NOBOSS:
            params: tuple[int] = params
            offset, = params

            if not lib.globals.groupBoss.sprite:
                self.pointer += offset - 1
        elif opcode == Opcode.STORE:
            params: tuple[int, typing.Union[int, float]] = params
            address, value = params

            self.vars[address] = value
        elif opcode == Opcode.RANDOM_INT:
            params: tuple[int, int, int] = params
            address, minValue, maxValue = params

            self.vars[address] = lib.globals.stgRandom.randint(minValue, maxValue)
        elif opcode == Opcode.RANDOM_FLOAT:
            params: tuple[int, float, float] = params
            address, minValue, maxValue = params

            self.vars[address] = minValue + (maxValue - minValue) * lib.globals.stgRandom.random()
        elif opcode == Opcode.INC:
            params: tuple[int] = params
            address, = params

            self.vars[address] += 1
        elif opcode == Opcode.DEC:
            params: tuple[int] = params
            address, = params

            self.vars[address] -= 1
        elif opcode == Opcode.ADD:
            params: tuple[int, typing.Union[int, float]] = params
            address, value = params

            self.vars[address] += value
        elif opcode == Opcode.SUB:
            params: tuple[int, typing.Union[int, float]] = params
            address, value = params

            self.vars[address] -= value
        elif opcode == Opcode.MUL:
            params: tuple[int, typing.Union[int, float]] = params
            address, value = params

            self.vars[address] *= value
        elif opcode == Opcode.DIV:
            params: tuple[int, int] = params
            address, value = params

            self.vars[address] = int(self.vars[address]) // int(value)
        elif opcode == Opcode.MOD:
            params: tuple[int, int] = params
            address, value = params

            self.vars[address] = int(self.vars[address]) % int(value)
        elif opcode == Opcode.FDIV:
            params: tuple[int, typing.Union[int, float]] = params
            address, value = params

            self.vars[address] /= value
        elif opcode == Opcode.SET_SCROLL_SPEED:
            params: tuple[float] = params
            speed, = params

            lib.globals.backgroundScrollSpeed = speed
        elif opcode == Opcode.SET_MASK_ALPHA:
            params: tuple[int] = params
            alpha, = params

            lib.globals.backgroundMaskAlpha = alpha
        elif opcode == Opcode.SET_MASK_SPEED:
            params: tuple[int] = params
            speed, = params

            lib.globals.backgroundMaskChangeSpeed = speed
        elif opcode == Opcode.LOAD_STAGE:
            params: tuple[str] = params
            scriptFile, = params

            self.halted = True
            with lib.utils.getResourceHandler(scriptFile) as f:
                lib.globals.stageEngine = Engine(f.read().decode())
        elif opcode == Opcode.SPAWN:
            # (-30, -80) (424, 478)
            params: tuple[float, float, float, str] = params
            x, y, angle, scriptFile = params

            enemy = lib.sprite.enemy.Enemy()
            enemy.position.update(x, y)
            enemy.angle = angle
            if scriptFile in enemyScriptCache and not os.environ.get('STRIKER_DEBUG_DISABLE_ENEMY_CACHE'):
                script = enemyScriptCache[scriptFile]
            else:
                with lib.utils.getResourceHandler(scriptFile) as f:
                    script = f.read().decode('utf-8')
            enemy.setScript(script)
        elif opcode == Opcode.BGM:
            params: tuple[str] = params
            bgmName, = params

            lib.sound.playBgm(bgmName)
        elif opcode == Opcode.BOSS_WARNING:
            lib.stg_overlay.overlayStatus[lib.stg_overlay.OverLayStatusIndex.WARNING_REMAIN] = 330
            lib.sound.sfx['BOSS_ALERT'].play(loops=1)
        elif opcode == Opcode.SET_CLEARED:
            lib.globals.allCleared = True
            lib.stg_overlay.overlayStatus[lib.stg_overlay.OverLayStatusIndex.CLEAR_REMAIN] = 240
            lib.sound.sfx['EXTEND_LIFE'].play()
        elif opcode == Opcode.DISABLE_CONTINUE:
            lib.globals.continueEnabled = False
        elif opcode == Opcode.SHOW_RESULT:
            if lib.globals.replayRecording:
                pygame.mixer.music.stop()
                lib.replay.stopRecording()
                lib.globals.nextScene = lib.scene.result
            else:
                lib.sound.playBgm('TITLE')
                lib.globals.nextScene = lib.scene.replay

        # elif opcode == Opcode.:
        #     params: tuple[] = params
        #      = params
        else:
            print('Unknown opcode:', opcode)


#------------------------------------------------------------------------------
# Imports
#------------------------------------------------------------------------------
import os
os.chdir('C:/Users/GarlefHupfer/OneDrive - ipri-institute.com/H/02-Projekte/40180003_IoC/03_Projektergebnisse/AP 9.3 Gesamtwirtschaftlichkeitsanalyse/3 IoC-Ontologie/python/')

import dash
import dash_bootstrap_components as dbc
from dash import html, dcc
import dash_daq as daq
import plotly.express as px
import datetime
import pandas
import plotly.graph_objects as go
from pm4py.objects.petri_net.importer import importer as pnml_importer
import graphviz
import plotly.figure_factory as pff
from dash.dependencies import Input, Output

#------------------------------------------------------------------------------
# Main Project Variables
#------------------------------------------------------------------------------
project_name = 'Betonieren'
project_path = 'testing/project/'
cost_plan_path = 'testing/project2/predicted_costs.csv'
actual_costs_path = 'testing/project2/actual_costs.csv'

curr_date = datetime.datetime(2022, 2, 10, 9, 0) #datetime.datetime.now()

# for cost diplay: use costs.sum(axis=1)

#------------------------------------------------------------------------------
# Initiate Dash App
#------------------------------------------------------------------------------
external_stylesheets = [dbc.themes.BOOTSTRAP]
app = dash.Dash(external_stylesheets=external_stylesheets, title='Projektübersicht')

for f in [f for f in os.listdir(app.config.assets_folder)]:
    os.remove(os.path.join(app.config.assets_folder, f))

#------------------------------------------------------------------------------
# Content
#------------------------------------------------------------------------------
app.layout = html.Div([
     dbc.Row([
         html.H1('Projektübersicht - ' + project_name, style={
             "paddingBottom": "10px"
             })
         ]),
     dbc.Row([
         dbc.Col([
             html.H2(f'Stand {curr_date.strftime("%Y-%m-%d %H:%M:%S")}', style={
                 'color': 'gray',
                 "paddingBottom": "20px"
                 })
             ],
             width=6
             ),
         dbc.Col([
             html.H3(['Projektübersicht'], style={'float': 'right'})
             ], width=2),
         dbc.Col([
             daq.ToggleSwitch(id='main-switch', value=True)
             ], width=1),
         dbc.Col([
             html.H3(['Wirtschaftlichkeitsanalyse'])
             ], width=3)
         ]),

        html.Div(['content loading...'], id='main-content')
    ],
    style={
        "padding": "50px",
        "fontFamily": "Arial",
        "fontSize": "0.9em"
        }
    )

# Main Callback: Show Project view or economic analysis
#------------------------------------------------------------------------------
@app.callback(Output('main-content', 'children'),
              Input('main-switch', 'value'))
def render_main_content(value):
    if not value: # Projektübersicht
        return [
            dbc.Row([
                dbc.Col([
                    dcc.Tabs(id="tabs-progress", value='tab-petri', children=[
                        dcc.Tab(label='Petri Net', value='tab-petri'),
                        dcc.Tab(label='Gantt Chart', value='tab-gantt'),
                        ]),
                    html.Div(id='tabs-progress-content', style={'border':'2px black solid', 'padding': '0px'}),
                    ],
                    width=8),
                 dbc.Col([
                     html.H2('Event Log'),
                     get_event_log()
                     ],
                     width=4,
                     style={
                         "paddingLeft": "10px",
                         "fontSize": "18px"})
                 ],
                 style={
                     "paddingBottom": "30px"
                     }),
             dbc.Row([
                 dbc.Col([
                     html.H2('Letzte Tätigkeiten', style={'paddingBottom': '20px'}),
                     get_last_activities()
                     ],style={"fontSize": "18px"}, width=3),
                 dbc.Col([
                     html.H2('Nächste Tätigkeiten', style={'paddingBottom': '20px'}),
                     get_next_activities()
                     ],style={"fontSize": "18px"}, width=5),
                 dbc.Col([
                     html.H2('Restliche Projektdauer', style={'paddingBottom': '20px'}),
                     get_remaining_duration()
                     ],style={"fontSize": "18px"}, width=4),
                 ])
            ]
    else: # Wirtschaftlichkeitsanalyse
        return [
            dbc.Row([
                dbc.Col([
                    html.H2(['Soll-Ist Vergleich der Projektkosten über die Zeit']),
                    get_cost_over_time()
                    ],
                    width=8),
                 dbc.Col([
                     html.H2('Projektkosten'),
                     '' #TODO: get_costs
                     ],
                     style={
                         "paddingLeft": "10px",
                         "fontSize": "18px"})
                 ],
                 style={
                     "paddingBottom": "30px"
                     }),
             dbc.Row([
                 dbc.Col([
                     html.H2('Kosten nach Partnern', style={'paddingBottom': '20px'}),
                     'Partnerkosten' #TODO: get_cost_by_partners
                     ],style={"fontSize": "18px"}, width=4),
                 dbc.Col([
                     html.H2('Kosten nach Kostenarten', style={'paddingBottom': '20px'}),
                     'Kostenartenkosten' #TODO: get_cost_by_kind
                     ],style={"fontSize": "18px"}, width=4),
                 dbc.Col([
                     html.H2('Restliche Projektkosten', style={'paddingBottom': '20px'}),
                     get_remaining_costs()
                     ],style={"fontSize": "18px"}, width=4),
                 ])
            ]

#------------------------------------------------------------------------------
# Page project view
#------------------------------------------------------------------------------

# Petri Net and Gantt Chart View
#------------------------------------------------------------------------------
@app.callback(Output('tabs-progress-content', 'children'),
              Input('tabs-progress', 'value'))
def render_progress(tab):
    if tab == 'tab-petri':
        return [html.Div('petri net is loading...', id='petri-net'),
                get_petri_filtering()]
    elif tab == 'tab-gantt':
        return get_gantt()

@app.callback(Output('petri-net', 'children'),
              Input('petri-filtering', 'value'))
def update_petri(petri_filter):
    generate_petri(petri_filter)

    fig = go.Figure()
    fig.add_layout_image(
            dict(
                source=app.get_asset_url('progress' + str(hash(str(petri_filter))) + '.gv.svg'),
                xref="x",
                yref="y",
                x=-5,
                y=0.5,
                sizex=10,
                sizey=4,
                sizing='contain',
                layer='below'
            )
    )
    fig.update_layout(xaxis={'range':[-4, 4], 'visible': False},
                      yaxis={'range':[-2, 2], 'visible': False},
                      margin={'pad': 0, 'l': 0, 't': 0, 'r': 0, 'b': 0},
                      dragmode='pan',
                      clickmode='none',
                      plot_bgcolor='#ffffff',
                      autosize=True)

    return dcc.Graph(figure=fig,
                     config = {'scrollZoom': True, 'displayModeBar': False})

def generate_petri(petri_filter):
    net, im, fm = pnml_importer.apply(project_path + 'temp/petri_net.pnml')

    if not os.path.exists(project_path + 'processes.csv'):
        print("WARNING: Couldn't find processes for coloring completed activities")

    if not os.path.exists(project_path + 'next_activities.csv'):
        print("WARNING: Couldn't find next activities for coloring")

    df = pandas.read_csv(project_path + 'processes.csv')
    next_activities = pandas.read_csv(project_path + 'next_activities.csv')
    completed = df[df['isfinished'] == True]
    res = get_ressources()

    nodes = {}
    arcs = []

    for node in net.transitions:
        nodes[node.name] = node.label

    for place in net.places:
        in_arcs = list(place.in_arcs)
        out_arcs = list(place.out_arcs)

        if len(in_arcs) == 1 and len(out_arcs) == 1:
            arcs.append([in_arcs[0].source.name, out_arcs[0].target.name])
        elif len(in_arcs) == 0 and len(out_arcs) == 1:
            arcs.append([place.name, out_arcs[0].target.name])
            nodes[place.name] = 'Start'
        elif len(in_arcs) == 1 and len(out_arcs) == 0:
            arcs.append([in_arcs[0].source.name, place.name])
            nodes[place.name] = 'End'
        else:
            print(f'WARNING: MORE THAN 1 ARCS IN PLACE {place.name}')

    dot = graphviz.Digraph('progress' + str(hash(str(petri_filter))), graph_attr={'rankdir':'LR'})

    for name in nodes.keys():
        if not nodes[name] == None:
            process = df[df['processname'] == nodes[name]]

            # determine colors
            if nodes[name] in list(completed['processname']):
                color = 'green'
            elif nodes[name] in list(next_activities['activity']):

                if process['isstarted'].iloc[0]:
                    color = 'limegreen'
                else:
                    if datetime.datetime.strptime(process['starttime'].iloc[0], '%d.%m.%Y %H:%M:%S') < curr_date:
                        color = 'red'
                    else:
                        color = 'orange'
            else:
                color = 'black'

            if not nodes[name] in ['Start', 'End']:
                if not petri_filter == res:
                    filter_true = False
                    for f in petri_filter:
                        print(f)
                        if f in process['resdescription'].iloc[0]:
                            print(f"[{f} is in {process['resdescription']}")
                            filter_true = True

                    if filter_true:
                        fontcolor = 'navy'
                    else:
                        fontcolor = 'gray40'
                else:
                    fontcolor = 'black'
            else:
                fontcolor = 'black'

            dot.node(name, nodes[name], shape='box', color=color, fontcolor=fontcolor)
        else:
            dot.node(name, '', shape='circle')

    for arc in arcs:
        if not arc[0] in nodes.keys():
            dot.node(arc[0], '', shape='circle')
        if not arc[1] in nodes.keys():
            dot.node(arc[1], '', shape='circle')

        dot.edge(arc[0], arc[1])

    dot.format= 'svg'
    dot.render(directory=app.config.assets_folder)

def get_petri_filtering(petri_filter='all'):
    res = get_ressources()
    if petri_filter == 'all':
        selection = res
    else:
        selection = petri_filter

    return dcc.Checklist(res, selection, id='petri-filtering', inputStyle={'margin-left': '20px', 'margin-right': '5px'})

def get_gantt():
    df = pandas.read_csv(project_path + 'processes.csv', usecols=['processname', 'starttime', 'endtime', 'isfinished'])#.sort_values('endtime', ascending=True)
    df['starttime'] = pandas.to_datetime(df['starttime'], dayfirst=True)
    df['endtime'] = pandas.to_datetime(df['endtime'], dayfirst=True)
    df = df.rename({'starttime': 'Start', 'endtime': 'Finish', 'processname': 'Task'}, axis=1)
    fig = pff.create_gantt(df)
    fig.update_yaxes(autorange="reversed")
    return dcc.Graph(figure=fig,
                     config = {'scrollZoom': True, 'displayModeBar': False})

# Upper Right: Event Log
#------------------------------------------------------------------------------
def get_event_log(max_rows=8):
    if not os.path.exists(project_path + 'event_log.csv'):
        return html.P("couldn't load event log, file is not existing")

    df = pandas.read_csv(project_path + 'event_log.csv').sort_values('timestamp', ascending=False).rename({'process': 'Tätigkeit', 'key': 'Faktor', 'from': 'Von', 'to': 'zu', 'timestamp': 'Zeitstempel'}, axis=1)
    return generate_table(df, 8)

# Bottom Left: Completed Activities
#------------------------------------------------------------------------------
def get_last_activities():
    if not os.path.exists(project_path + 'processes.csv'):
        return html.P("couldn't load last activites, processes are not existing")

    df = pandas.read_csv(project_path + 'processes.csv', usecols=['processname', 'endtime', 'isfinished']).sort_values('endtime', ascending=False).rename({'processname': 'Tätigkeit', 'endtime': 'Erledigt am'}, axis=1)
    completed = df[df['isfinished'] == True]
    completed = completed.drop(['isfinished'], axis=1)
    return generate_table(completed, 5)

# Bottom Middle: Next Activities with relevance
#------------------------------------------------------------------------------
def get_next_activities(max_rows=5):
    if not os.path.exists(project_path + 'next_activities.csv'):
        return html.P("couldn't load next activities, file is not existing")

    df = pandas.read_csv(project_path + 'next_activities.csv').sort_values('until', ascending=False).rename({'activity': 'Tätigkeit', 'until': 'Erledigen bis', 'relevance': 'Dringlichkeit', 'starttime': 'Startdatum'}, axis=1)
    colors = []

    for index, row in df.iterrows():
        color = 'black'

        if row['started']:
            color = 'green'

        colors.append(color)

    return html.Table([
        html.Thead(
            html.Tr([html.Th(col, style={'padding': '10px'}) for col in df.columns if col in ['Tätigkeit', 'Erledigen bis', 'Dringlichkeit', 'Startdatum']])
        ),
        html.Tbody([
            html.Tr([
                html.Td(df.iloc[i][col], style={'paddingLeft': '10px', 'paddingRight': '10px'}) for col in df.columns if col in ['Tätigkeit', 'Erledigen bis', 'Dringlichkeit','Startdatum']
            ], style={'color': colors[i]}) for i in range(min(len(df), max_rows))
        ])
    ])

# Bottom Right: Remaining Duration
#------------------------------------------------------------------------------
def get_remaining_duration():
    if not os.path.exists(project_path + 'temp/duration.csv'):
        return html.P("couldn't load remaining duration, file is not existing")

    try:
        with open(project_path + 'temp/duration.csv', 'r') as f:
            durs = [float(l) for l in f.readlines()]
    except:
        return html.P("couldn't load remaining duration, file is not accessible, retrying...")

    fig = px.histogram(durs)
    fig.update_layout({'xaxis': {'title': {'text': 'Restdauer (in h)'}},
                       'yaxis': {'title': {'text': 'Häufigkeit'}},
                       'showlegend': False})
    return dcc.Graph(figure=fig, config = {'displayModeBar': False})

#------------------------------------------------------------------------------
# Page economic analysis
#------------------------------------------------------------------------------

# Main Cost over Time
#------------------------------------------------------------------------------
def get_cost_over_time():
    if not os.path.exists(project_path + 'processes.csv'):
        return html.P("couldn't load processes, file is not existing")
    try:
        proc = pandas.read_csv(project_path + 'processes.csv')
    except:
        return html.P("couldn't load processes, file is not accessible, retrying...")

    if not os.path.exists(cost_plan_path):
        return html.P("couldn't load cost plan, file is not existing")
    try:
        planned_costs = pandas.read_csv(cost_plan_path)
    except:
        return html.P("couldn't load cost plan, file is not accessible, retrying...")

    if not os.path.exists(actual_costs_path):
        return html.P("couldn't load actaul costs, file is not existing")
    try:
        actual_costs = pandas.read_csv(actual_costs_path)
    except:
        return html.P("couldn't load actaul costs, file is not accessible, retrying...")

    df = pandas.merge(proc, planned_costs, on='processname').sort_values('endtime')
    df['total_planned_costs'] = df['personal'] + df['material'] + df['transport'] + df['vertrieb'] + df['equipment']
    df['accumulated_planned_costs'] = df['total_planned_costs'].cumsum()
    df = df.drop(['personal', 'material', 'transport', 'vertrieb', 'equipment', 'total_planned_costs'], axis=1)

    df = pandas.merge(df, actual_costs, on='processname')
    df['total_actual_costs'] = df['personal'] + df['material'] + df['transport'] + df['vertrieb'] + df['equipment']
    df['accumulated_actual_costs'] = df['total_actual_costs'].cumsum()
    df = df.drop(['personal', 'material', 'transport', 'vertrieb', 'equipment', 'total_actual_costs'], axis=1)

    graph_df = df[['endtime', 'accumulated_planned_costs', 'accumulated_actual_costs']]
    fig = go.Figure()

    fig.add_trace(go.Scatter(x=graph_df['endtime'], y=graph_df['accumulated_planned_costs'], mode='lines'))
    fig.add_trace(go.Scatter(x=graph_df['endtime'], y=graph_df['accumulated_actual_costs'], mode='lines'))

    #fig.update_layout({'xaxis': {'title': {'text': 'Verbleibende Kosten (in EUR)'}},
    #                   'yaxis': {'title': {'text': 'Häufigkeit'}},
    #                   'showlegend': False})
    return dcc.Graph(figure=fig, config = {'displayModeBar': False})

def get_remaining_costs():
    if not os.path.exists(project_path + 'temp/costs.csv'):
        return html.P("couldn't load remaining duration, file is not existing")
    try:
        df = pandas.read_csv(project_path + 'temp/costs.csv')
    except:
        return html.P("couldn't load remaining duration, file is not accessible, retrying...")

    total_costs = df.sum(axis=1).to_list()

    fig = px.histogram(total_costs)
    fig.update_layout({'xaxis': {'title': {'text': 'Verbleibende Kosten (in EUR)'}},
                       'yaxis': {'title': {'text': 'Häufigkeit'}},
                       'showlegend': False})
    return dcc.Graph(figure=fig, config = {'displayModeBar': False})

#------------------------------------------------------------------------------
# Helper Functions
#------------------------------------------------------------------------------
def generate_table(dataframe, max_rows=10):
    return html.Table([
        html.Thead(
            html.Tr([html.Th(col, style={'padding': '10px'}) for col in dataframe.columns])
        ),
        html.Tbody([
            html.Tr([
                html.Td(dataframe.iloc[i][col], style={'paddingLeft': '10px', 'paddingRight': '10px'}) for col in dataframe.columns
            ]) for i in range(min(len(dataframe), max_rows))
        ])
    ])

def get_ressources():
    df = pandas.read_csv(project_path + 'processes.csv')
    ressources = df['resdescription'].unique()
    res = []
    for r in ressources:
        r = r.replace('[', '').replace(']', '')
        while '|' in r:
            res.append(r[:r.index('|')].lstrip().rstrip().lstrip("'").rstrip("'"))
            r = r[r.index('|') + 1:]
        res.append(r.lstrip().rstrip().lstrip("'").rstrip("'"))
    return list(dict.fromkeys(res))

if __name__ == '__main__':
    app.run_server(debug=True)#, dev_tools_hot_reload=False)


from hard_port.serial import serialposix
from hard_port.serial.tools import list_ports_linux

class ArduinoClient():
    serial_port = None

    @staticmethod
    def get_arduino_serial():
        ports = list(list_ports_linux.comports())
        print(ports)

        for p in ports:
            if p[1]:
                print('Arduino on port : ' + p[1])
                ser = serialposix.Serial(p[0], 9600, timeout=0.01)
                return ser
            else:
                print("No Arduino Device was found connected to the computer")

    @staticmethod
    def init():
        if ArduinoClient.serial_port is None:
            ArduinoClient.serial_port = ArduinoClient.get_arduino_serial()
            print('INIT ARDUINO CONNECTION')
        # sudo chown maxim /dev/ttyACM0
        # sudo ln - s /dev/ttyACM0 /dev/ttyACM0

    @staticmethod
    def write(str):
        ArduinoClient.serial_port.write(str.encode())

    @staticmethod
    def unlock():
        ArduinoClient.write('unlock\n')

    @staticmethod
    def lock():
        ArduinoClient.write('lock\n')

    @staticmethod
    def read():
        ArduinoClient.write('sayState\n')
        i = 0
        text = ''
        end_message_symbol='}'
        current_symbol = ''
        while current_symbol != end_message_symbol:
            current_symbol = ArduinoClient.serial_port.read().decode("utf-8")
            text = text+current_symbol
            print('Read symbol : ' + current_symbol)
            i = i + 1
        return text


import streamlit as st
####Importing Necessary Libraries
import re
import pandas as pd
import io
from io import StringIO
import seaborn as sns
import emoji

# Page title
st.set_page_config(page_title='ðŸ¦œðŸ”— WhatsApp Chat Analysis', layout="wide")
st.title('ðŸ¦œðŸ”— WhatsApp Chat Analysis')
st.write("#")
# creating a single-element container
placeholder = st.empty()

# File upload
with st.container():
    uploaded_file = st.file_uploader('Upload your chat file', type='txt')
#with st.form('myform', clear_on_submit=True):
#    submitted = st.form_submit_button('Run Analysis', disabled=not(uploaded_file))
st.write("#")
##Parsing whataspp messages to dataframe
if uploaded_file is not None:
    # To read file as bytes:
    bytes_data = uploaded_file.getvalue()

    # To convert to a string based IO:
    stringio = StringIO(uploaded_file.getvalue().decode("utf-8"))

    # To read file as string:
    string_data = stringio.read()

    whatsapp_regex = r"(\d{2}/\d{2}/\d{4}), (\d{2}:\d{2}) - ([^:]*): (.*?)(?=\d{2}/\d{2}/\d{4}, \d{2}:\d{2} - [^:]*|\Z)"
    matches = re.findall(whatsapp_regex, string_data, re.MULTILINE | re.DOTALL)
    df = pd.DataFrame(matches, columns=["date", "time", "name", "message"])
    df['date'] = pd.to_datetime(df['date'],format='%d/%m/%Y')
    df['time'] = pd.to_timedelta(df['time']+':00')
    df['datetime']= df["date"] + df['time']
    #df = df.head(10)
    #st.dataframe(df['message'])

    with st.container():
        #create 3 columns
        Chat_Members, Message_Count, Peak_Time, Media_Shared_Count = st.columns(4)
        # fill in those three columns with respective metrics
        Chat_Members.metric(
            label = "Chat_Members",
            value = int(len(df['message'])),
            delta = len(df['message']) - 10
        )
        Message_Count.metric(
            label = "Message_Count",
            value = int(len(df['message'])),
            delta = len(df['message']) - 10
        )
        Peak_Time.metric(
            label = "Peak_Time",
            value = int(len(df['message'])),
            delta = len(df['message']) - 10
        )
        Media_Shared_Count.metric(
            label = "Media_Shared_Count",
            value = int(len(df['message'])),
            delta = len(df['message']) - 10
        )
    st.write("#")
    with st.container():
        # create two columns for charts
        fig_col1, fig_col2 = st.columns(2)
        with fig_col1:
            st.markdown("##### :red[Most Active Member of the group]")
            ##Finding pattern of messager
            pattern = re.compile('\d+:\d+\s+-\s+([a-zA-Z0-9]+\s?[a-zA-Z0-9]+\s?[a-zA-Z0-9]+\s?):\s+')
            messengers = re.findall(pattern,string_data)
            count_messages={}
            for each in messengers:
                if each in count_messages.keys():
                    count_messages[each]+=1
                else:
                    count_messages[each]=1
            message_cnt = pd.DataFrame.from_dict([count_messages])

            message_cnt = message_cnt.T.sort_values(by = 0, ascending=False)
            message_cnt = message_cnt.rename(columns={0: 'Mssg_Count'})

            #EDA for general understanding of the distribution of the dataset.
            message_cnt['Names'] = message_cnt.index
            #sns.set(rc={'figure.figsize':(800,600)})
            ax =sns.barplot(x = 'Names', y = 'Mssg_Count' ,data = message_cnt.head(5), estimator = sum, palette=("crest"))
            ax.set_title('Most Active Member of the group', size = 20)
            ax.set(ylabel='No. of Messages')
            st.bar_chart(data = message_cnt.head(5), x = 'Names', y = 'Mssg_Count')
            st.write(ax)

        with fig_col2:
            st.markdown("##### :red[Which hour of the day were most messages sent?]")
            hour_pattern = '(\d+):\d+\s+-\s+\w+\s?\w+?\s?\w+\s?\w+:\s'
            hours = re.findall(hour_pattern,string_data)
            time = pd.DataFrame({'hours':hours})
            time['count'] = [1]* len(time)
            time = time.sort_values(by = 'hours', ascending = True)
            #EDA for general understanding of the distribution of the dataset.
            st.bar_chart(data = time, x = 'hours', y = 'count')
            st.write(ax)
        st.write("#")
        with st.container():
            figure1, figure2, figure3 = st.columns(3)
            df['day_of_week'] = df['date'].dt.dayofweek

            # map the day of the week number to its name
            df['day_of_week'] = df['day_of_week'].map({
                0: 'Monday',
                1: 'Tuesday',
                2: 'Wednesday',
                3: 'Thursday',
                4: 'Friday',
                5: 'Saturday',
                6: 'Sunday'
            })
            df['month_of_date'] = df['date'].dt.month
            df['month_of_date'] = df['month_of_date'].map({
                1: 'Jan',
                2: 'Feb',
                3: 'Mar',
                4: 'Apr',
                5: 'May',
                6: 'Jun',
                7: 'Jul',
                8: 'Aug',
                9: 'Sep',
                10: 'Oct',
                11: 'Nov',
                12: 'Dec'
            })
            df['year'] = df['date'].dt.year
            df['Period'] = df['month_of_date'].map(str) + "-" + df['year'].map(str)
            with figure1:
                st.markdown("##### :red[Most Busy Day]")
                #EDA for general understanding of the distribution of the dataset.
                df_most_busy_day = df[['day_of_week', 'month_of_date']].groupby('day_of_week').count()
                df_most_busy_day = df_most_busy_day.sort_values(by = 'month_of_date', ascending = False)
                df_most_busy_day['day_of_week'] = df_most_busy_day.index
                st.bar_chart(data = df_most_busy_day, x = 'day_of_week', y = 'month_of_date')

            with figure2:
                st.markdown("##### :red[Who sent most media files]")
                list_irrelevant_txt_v1 = ["<Media omitted>\n"]
                df_v4 = df[df['message'].isin(list_irrelevant_txt_v1)]
                df_v4['count'] = 1 * len(df_v4)
                df_v4 = df_v4[['name','count']].groupby(['name']).sum()
                df_v4 = df_v4.sort_values(by = 'count', ascending=False).head(5)
                #EDA for general understanding of the distribution of the dataset.
                df_v4['name'] = df_v4.index
                st.bar_chart(data = df_v4, x = 'name', y = 'count')

            with figure3:
                st.markdown("##### :red[Who used emojis often]")
                emoji_1 = re.compile('[\\u203C-\\u3299\\U0001F000-\\U0001F644]')
                df['emoji_list']= pd.DataFrame(filter(emoji_1.match, df['message']))
                #EDA for general understanding of the distribution of the dataset.
                names_with_most_emoji = df[['name','emoji_list']].dropna().groupby(by = 'name').count().sort_values(by = 'emoji_list', ascending = False).head(5)
                names_with_most_emoji['name'] = names_with_most_emoji.index
                st.bar_chart(data = names_with_most_emoji, x = 'name', y = 'emoji_list')


def f(x):
	if (x == 0):
		return "INSOMNIA"
	digits = [0] * 10
	current = x
	while True:
		for c in str(current):
			digits[int(c)] = 1
		if (sum(digits)) == 10:
			return current
		current += x

n = int(input())
for i in range(n):
	x = f(int(input()))
	print("Case #{0}: {1}".format(i+1, x))


class partyanimal:
    x=0
    name = ""
    def __init__(self, z):
        print("Hello to Constructor")
        self.name = z
        print(self.name,"name of that person")

    def party(self):
        self.x = self.x + 10
        print(self.x)
    def __del__(self):
        print("Bye Constructor")
an = partyanimal("Haguli")

an.party()
an.party()

class PartyAnimal:
    l = 0
    name = ''
    def __init__(self, nam):
        self.name = nam
        print(self.name,'constructed')
    def party(self):
        self.l = self.l + 1
        print(self.name,'party count',self.l)

q = PartyAnimal('Quincy')
m = PartyAnimal('Miya')

q.party()
m.party()
q.party()


from AccessControl import ClassSecurityInfo
from App.ImageFile import ImageFile
from Globals import InitializeClass
from naaya.groupware.groupware_site import GroupwareSite
from Products.NaayaCore.managers.utils import utils

class EnviroWindowsSite(GroupwareSite):	# NySite):
    """ """
    meta_type = "Groupware site"
    security = ClassSecurityInfo()

    ew_common_css = ImageFile('www/ew_common.css', globals())
    ew_print_css = ImageFile('www/ew_print.css', globals())
    ew_style_css = ImageFile('www/ew_style.css', globals())

    manage_options = (
        GroupwareSite.manage_options
    )

    security.declarePublic('stripAllHtmlTags')
    def stripAllHtmlTags(self, p_text):
        """ """
        return utils().utStripAllHtmlTags(p_text)

InitializeClass(EnviroWindowsSite)


import logging

from sqlalchemy.engine import Engine
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import sessionmaker
from SQLAlchemy.ex_sa_00 import create_db_engine
from SQLAlchemy.ex_sa_05 import Customer
from SQLAlchemy.ex_sa_12 import Base, Account, Securities, Trades

logging.basicConfig(format='%(asctime)s - %(message)s', level=logging.INFO)

def create_trades_table(engine: Engine) -> bool:
    status = False

    if not engine.dialect.has_table(engine, 'trades'):
        Base.metadata.create_all(db_engine)

        logging.info("Created the trades table !!!")

        status = True
    else:
        logging.info("The trades table already exists !!!")

    return status

def insert_trades(engine: Engine):
    if engine.dialect.has_table(engine, 'trades'):
        Session = sessionmaker(bind=engine)

        session = Session()

        try:
            t1 = Trades(trade_type='B', quantity=100, aid=1001, sid=1)
            t2 = Trades(trade_type='B', quantity=300, aid=1001, sid=3)
            t3 = Trades(trade_type='B', quantity=50, aid=1003, sid=1)
            t4 = Trades(trade_type='B', quantity=150, aid=1003, sid=2)
            t5 = Trades(trade_type='S', quantity=100, aid=1001, sid=3)
            t6 = Trades(trade_type='S', quantity=50, aid=1003, sid=2)

            tlst = [t1, t2, t3, t4, t5, t6]

            session.add_all(tlst)
            session.commit()

            logging.info("Inserted record(s) for 6 trades:")

            for tr in tlst:
                logging.info("\t==> %s" % tr)
        except SQLAlchemyError as e:
            logging.error(e)

        session.close()
    else:
        logging.info("The trades table *DOES NOT* exist !!!")

def query_trades(engine: Engine):
    if engine.dialect.has_table(engine, 'account') and engine.dialect.has_table(engine, 'customer') and \
            engine.dialect.has_table(engine, 'securities') and engine.dialect.has_table(engine, 'trades'):
        Session = sessionmaker(bind=engine)

        session = Session()

        logging.info("SQL => %s" % session.query(Customer.first_name, Customer.last_name, Account.acct_name,
                                                 Trades.trade_dt, Trades.trade_type, Trades.quantity,
                                                 Securities.symbol, Securities.price) \
                     .select_from(Trades).join(Account).join(Securities).join(Customer))
        recs = session.query(Customer.first_name, Customer.last_name, Account.acct_name,
                             Trades.trade_dt, Trades.trade_type, Trades.quantity,
                             Securities.symbol, Securities.price) \
            .select_from(Trades).join(Account).join(Securities).join(Customer)
        if recs.count() > 0:
            logging.info("< -------------------------")
            for r in recs:
                logging.info(r)
            logging.info("------------------------- >")
        else:
            logging.info("Record(s) for trades by customers *DOES NOT* exist !!!")

        session.close()
    else:
        logging.info("The account/customer/securities/trades table(s) *DOES NOT* exist !!!")

if __name__ == "__main__":
    db_engine = create_db_engine()
    if create_trades_table(db_engine):
        insert_trades(db_engine)
    query_trades(db_engine)