# 1 - Import packages
import pygame
from pygame.locals import * #constants
import sys #for quiting the window

#here is out important object file
import objectFile
import scene_initilzer
import classObjRef

# 2 - Define constants
SCREEN_COL = (0, 0, 0)
WINDOW_WIDTH = 640
WINDOW_HEIGHT = 480
FRAMES_PER_SECOND = 60

QUIT_FLAG = False
# 3 - Initialize the world

pygame.init()
window = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
clock = pygame.time.Clock()

#scene initlizer data

def game_initiater():
   objectFile.SCENE_NO = scene_initilzer.currentScene
   for sceneName , sceneInfo  in scene_initilzer.all_scn.items():
      objectFile.OBJECT_ARRAY[sceneName] = []

      info , meshinfo = sceneInfo
   #here is the initilizationfo the SCNE INFO
      objectFile.SCENE_INFO[sceneName] = info

   #here is the iniltization of the OBJECT ARRAY
   #flusing the array before
      objectFile.OBJECT_ARRAY[sceneName].clear()

      for mesh in meshinfo:
         meshtype , meshproperties = mesh
         newmesh = classObjRef.CLASS_ARRAY[meshtype]()

         newmesh.x = meshproperties['x']
         newmesh.y = meshproperties['y']
         newmesh.width = meshproperties['w']
         newmesh.height = meshproperties['h']
         newmesh.name = meshproperties['name']
         newmesh.type = meshproperties['type']
         newmesh.color = meshproperties['color']
         newmesh.angle = meshproperties['angle']
         newmesh.pivotOffset = meshproperties['offset']
         objectFile.OBJECT_ARRAY[sceneName].append(newmesh)

#unique id initilatization to each mesh

#setting the mesh
   for object in objectFile.OBJECT_ARRAY[objectFile.SCENE_NO]:
      object.id = objectFile.idGenerator
      objectFile.idGenerator+=1

#fist we load a window in each mesh
   for object in objectFile.OBJECT_ARRAY[objectFile.SCENE_NO]:
      object.loadinfo(window)

#here just before the loop we calla the create functin of all obects
   for object in objectFile.OBJECT_ARRAY[objectFile.SCENE_NO]:
      object.oncreate()

game_initiater()

while not QUIT_FLAG:
    #here we are settin gthe scene
    scne_data = objectFile.SCENE_INFO[objectFile.SCENE_NO]
    if WINDOW_HEIGHT != scne_data[0][1] and WINDOW_WIDTH != scne_data[0][0]:
       WINDOW_WIDTH , WINDOW_HEIGHT = scne_data[0]
       window = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))

    SCREEN_COL = scne_data[1] #setting the col

    #collectiong the light masked mesh
    objectFile.LIGHT_MASK.clear()
    for i , object in enumerate(objectFile.OBJECT_ARRAY[objectFile.SCENE_NO]):
       objectFile.LIGHT_MASK.append(i)

 # 7 - Check for and handle event
    for event in pygame.event.get(): #event loop
 # Clicked the close button? Quit pygame and end the program
      if event.type == pygame.QUIT:
         pygame.quit()
         sys.exit()

      #here im hanfling the mose events
      if event.type == pygame.MOUSEBUTTONDOWN:
        for object in objectFile.OBJECT_ARRAY[objectFile.SCENE_NO]  :object.onMouseDown(event)
      if event.type == pygame.MOUSEBUTTONUP:
        for object in objectFile.OBJECT_ARRAY[objectFile.SCENE_NO]  :object.onMouseUp(event)

        #here im handling the keyboard events

      if event.type == pygame.KEYDOWN:
        for object in objectFile.OBJECT_ARRAY[objectFile.SCENE_NO] :object.onKeyPressed(event.key)
      if event.type == pygame.KEYUP:
        for object in objectFile.OBJECT_ARRAY[objectFile.SCENE_NO]  :object.onKeyReleased(event.key)

      keys = pygame.key.get_pressed()
      for object in objectFile.OBJECT_ARRAY[objectFile.SCENE_NO]  :object.onKeyDown(keys)

      #here ar ethe code to rende the evnt of the interal wigets

      for object in objectFile.OBJECT_ARRAY[objectFile.SCENE_NO]  :object.eventHandler(event)

   #here we handhe the collsions
    meshs = objectFile.OBJECT_ARRAY[objectFile.SCENE_NO]
    for k,  object in enumerate(meshs):
       for  object2 in meshs[k+1:]:
          if object.Rect and object2.Rect:
            if object.Rect.colliderect(object2.Rect):
               direction1 = [x - y for (x , y) in zip(object.center,object2.center)]
               direction2 = [x - y for (x , y) in zip(object2.center,object.center)]
               object.onCollisionWith(object2 , direction1)
               object2.onCollisionWith(object , direction2)

   #8 - Do any "per frame" actions
   #fluhint the ligth mask

    for i , object in enumerate(objectFile.OBJECT_ARRAY[objectFile.SCENE_NO]):
        object.update()

 # 9 - Clear the window
#98   Chapter 5
    window.fill(SCREEN_COL) #equivalent to clear

 # 10 - Draw all window elements

    for object in objectFile.OBJECT_ARRAY[objectFile.SCENE_NO]:
        object.render()

 # 11 - Update the window

    pygame.display.update()
 # 12 - Slow things down a bit
    clock.tick(FRAMES_PER_SECOND)

    #here to handle the break out of the game loop from te inner object
    #
    for object in objectFile.OBJECT_ARRAY[objectFile.SCENE_NO]:

        if object.restart_flag:
           object.restart_flag = False
           game_initiater()

        if object.quit_flag:

           QUIT_FLAG = True


from multiprocessing import Queue, Lock

class CustomQueue:
    def __init__(self, levels: int = 1):
        self._queues = {}
        self._lock = Lock()
        for i in range(levels):
            self._queues[str(i)] = {"queue": Queue(), "size": 0}

    def __repr__(self):
        return f"<Queue: total_levels={len(self._queues.keys())}, level_inputs={','.join(self._queues.keys())}>"

    def put(self, item, level: int):
        """PUT AN ITEM INTO THE QUEUE BASED ON IT'S LEVEL"""
        if 0 <= level <= len(self._queues.keys()):
            with self._lock:
                self._queues[str(level)]["queue"].put(item)
                self._queues[str(level)]["size"] += 1
        else:
            raise Exception("level must be valid")

    def get(self):
        """GET AN ITEM FROM THE FIRST QUEUE"""
        for queue in self._queues.keys():
            if not self._queues[queue]["queue"].empty():
                with self._lock:
                    item = self._queues[queue]["queue"].get()
                    self._queues[queue]["size"] -= 1
                return item
        return None

    def qsize(self) -> object:
        """GET THE SIZE OF THE ENTIRE QUEUE"""
        qsize = 0
        for queue in self._queues.values():
            qsize += queue["size"]
        return qsize

if __name__ == '__main__':
    x = CustomQueue(levels=2)
    print(x)

    x.put("hey", 0)
    x.put("dude", 1)
    print(x.qsize())
    print(x.get())
    print(x.qsize())


from geoi import parameter
import  wx

import geoi.parameter

class BaseValidator(wx.PyValidator):
    """
    """

    def Clone (self):
        import copy
        return copy.copy(self)
        #return self.__class__()

#    def Validate(self, window):     # window here is the *parent* of the ctrl
#        """
#        Because each operation on the control is vetted as it's made,
#        the value of the control is always valid.
#        """
#        return 1

    def OnChar(self, event):
        pass

    def TransferToWindow(self):
        return True # Prevent wx.Dialog from complaining.

    def TransferFromWindow(self):
        return True # Prevent wx.Dialog from complaining.

INVALID_COLOR = 'RED'

class AposterioriValidator(BaseValidator):

    def __init__(self, check_callback, invalid_color=INVALID_COLOR):
        " check_callback is a function taking the value as argument "
        BaseValidator.__init__(self)
        self._invalid_color = invalid_color
        self._check = check_callback
        self._nbcalls = 0

        self.Bind(wx.EVT_KILL_FOCUS, self._onFocus)
        self.Bind(wx.EVT_TEXT, self._onText)
        self.Bind(wx.EVT_CHAR, self._onChar)
        self.Bind(wx.EVT_WINDOW_CREATE, self._onWinCreate)

    def Clone(self):
        return self.__class__(self._check, self._invalid_color)

    def setValidEditorValue(self, editor, isValid):
        "set if an editor has a valid value by displaying graphically if the value is invalid"

        if isValid:
            editor.SetBackgroundColour( self._default_bg_color )
        else:
            editor.SetBackgroundColour( self._invalid_color )
        editor.Refresh()

    def _onWinCreate(self, evt):
        #print "_onWinCreate"
        self._validate(evt)

    def _onText(self, evt):
        #print "_onText"
        self._validate(evt)

    def _onFocus(self, evt):
        #print "_onFocus"
        self._validate(evt)

    def _onChar(self, evt):
        #print "_onChar"
        self._validate(evt)

    def _validate(self, evt):
        editor = evt.GetEventObject()
        self.doTheValidation(editor)
        evt.Skip()

    def doTheValidation(self, editor):
        if self._nbcalls == 0: # first time
            self._default_bg_color = editor.GetBackgroundColour()
        self._nbcalls += 1

        value = editor.GetValue()
        status = (self._check(value) == True)
        self.setValidEditorValue(editor, status)

        return status

    def Validate(self, win):     # window here is the *parent* of the ctrl
        """
        """

        status = self.doTheValidation(self.GetWindow())
#        print ("Validate(self, win) => %s" % status), self
        return status

class ParameterValidator(AposterioriValidator):
    def __init__(self, param, invalid_color=INVALID_COLOR):
        " check_callback is a function taking the value as argument "
        AposterioriValidator.__init__(self,self._check_callback, invalid_color)
        self._param = param

        self.Bind(wx.EVT_KILL_FOCUS, self._onFocus)
        self.Bind(wx.EVT_TEXT, self._onText)
        self.Bind(wx.EVT_CHAR, self._onChar)
        self.Bind(wx.EVT_WINDOW_CREATE, self._onWinCreate)

    def Clone(self):
        return self.__class__(self._param, self._invalid_color)

    def _check_callback(self, v):
        return self._param.checkValue(v)

    def TransferToWindow(self):
#        print " TransferToWindow ", self
        self.GetWindow().SetValue( str(self._param.getValue()) )
        return True # Prevent wx.Dialog from complaining.

    def TransferFromWindow(self):
#        print " TransferFromWindow ", self
        self._param.setValueFromString( str(self.GetWindow().GetValue()) )
        return True # Prevent wx.Dialog from complaining.

    def __str__(self):
        s = "ParameterValidator for parameter %s of value %s, current window value:%s" \
             % (self._param.getName(),self._param.getValue(), self.GetWindow().GetValue() )
        return s

def IS_FLOAT(v):
    try:
        float(v)
    except:
        return False
    return True

if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = wx.Frame(None, -1, "")

    mains = wx.BoxSizer(wx.VERTICAL)

    sizer = wx.BoxSizer(wx.HORIZONTAL)
    sizer.Add( wx.StaticText(frame, -1 , "test TextValidator : isdigit") )

    validator = AposterioriValidator(lambda v: str(v).isdigit())
    fc = wx.TextCtrl(frame, -1 , "", validator=validator)
    sizer.Add(fc)

    mains.Add( sizer )

    sizer = wx.BoxSizer(wx.HORIZONTAL)
    sizer.Add( wx.StaticText(frame, -1 , "test TextValidator : isfloat") )

    validator = AposterioriValidator(lambda v: IS_FLOAT(v))
    fc = wx.TextCtrl(frame, -1 , "", validator=validator)
    sizer.Add(fc)
    mains.Add( sizer )

    p = parameter.Parameter("parameter", "",
                           'log of the equilibrium constant at 25 Celcius degrees'
                           , parameter.IS_NUMBER)
    sizer = wx.BoxSizer(wx.HORIZONTAL)
    sizer.Add( wx.StaticText(frame, -1 , "test ParameterValidator ") )
    fc = wx.TextCtrl(frame, -1 , "", validator=ParameterValidator(p))
    sizer.Add(fc)
    mains.Add( sizer )

    frame.SetSizerAndFit(mains)
    frame.Show(True)
    app.MainLoop()


import pandas as pd
import numpy as np

import matplotlib.pyplot as plt

import seaborn as sns
from scipy import stats

import sklearn
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics
from sklearn.metrics import classification_report, confusion_matrix

# 1_1
# ______________________________________________________________________________
banknotes = pd.read_csv(
    'data_banknote_authentication.txt', sep=",")

banknotes.columns = ['Variance', 'Skewness', 'Curtosis', 'Entropy', 'Class']

print(banknotes)
class_list = banknotes['Class'].to_list()
class_list = [int(s) for s in class_list]
color_list = []

for i in range(len(class_list)):
    if class_list[i] == 0:
        color_list.append("Green")
    else:
        color_list.append("Red")

banknotes['Color'] = color_list

# 1_2
# ______________________________________________________________________________
all = (banknotes.std(axis=0, skipna=True))
print(banknotes.mean(axis=0, skipna=True))
print(all)
class_0 = banknotes[banknotes['Color'] == "Green"]
class_1 = banknotes[banknotes['Color'] == "Red"]
print(class_0.std(axis=0, skipna=True))
print(class_0.mean(axis=0, skipna=True))
print(class_1.std(axis=0, skipna=True))
print(class_1.mean(axis=0, skipna=True))
# finish table

# 2_1
# ______________________________________________________________________________
# split train and test

X = banknotes.iloc[:, :-1].values
y = banknotes.iloc[:, ].values

X_train, X_test, = train_test_split(banknotes, test_size=0.53, random_state=42)

# split into test_0 test_1
train_0 = X_train[X_train['Color'] == "Green"]
train_1 = X_train[X_train['Color'] == "Red"]

# plot in seaborn
sns.pairplot(train_0)
sns.pairplot(train_1)

# plt.show()

# 2_2-3
# ______________________________________________________________________________
# come up with strategy fake = curtosis <5 , skewness > 0 , variance <2.5

def predict(df):
    if (df['Curtosis'] < 5) and (df['Skewness'] >= 0) and (df['Variance'] <= 1):
        return 'Red'
    else:
        return 'Green'

X_test['Predict'] = X_test.apply(predict, axis=1)

print(X_test)

# 2_4
# ______________________________________________________________________________
print("My strategy: ")
print(confusion_matrix(X_test['Color'], X_test['Predict']))
tp, fn, fp, tn = confusion_matrix(X_test['Color'], X_test['Predict'],
                                  labels=["Green", "Red"]).reshape(-1)
print(tp, fn, fp, tn)
accuracy = round((((tp + tn) / (fn + fp + tp + tn)) * 100), 2)
true_pos = round(((tp / (tp + fn)) * 100), 2)
true_neg = round(((tn / (tn + fp)) * 100), 2)

print("TP     FP     TN     FN     Accuracy    TPR     TNR")
print(tp, "  ", fp, "  ", tn, "  ", fn, "   ", accuracy, "     ", true_pos, " ",
      true_neg)

# 3_1-3
# ______________________________________________________________________________
# scale data
del banknotes['Color']

banknotes = banknotes.astype(float)
X = banknotes.iloc[:, :-1].values
y = banknotes.iloc[:, 4].values

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.50)
scaler = StandardScaler()
scaler.fit(X_train)

X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

# k_models and plotting
k_range = [3, 5, 7, 9, 11]
scores = {}
scores_list = []
for k in k_range:
    knn = KNeighborsClassifier(n_neighbors=k)
    knn.fit(X_train, y_train)
    y_pred = knn.predict(X_test)
    scores[k] = metrics.accuracy_score(y_test, y_pred)
    scores_list.append(metrics.accuracy_score(y_test, y_pred))

print("Accuracy Scores for K: ", scores)

plt.plot(k_range, scores_list)
plt.xlabel("K")
plt.ylabel("Testing Accuracy")
plt.show()

best_k = max(scores, key=scores.get)
print(best_k)

knn1 = KNeighborsClassifier(n_neighbors=best_k)
knn1.fit(X_train, y_train)

y_pred_best = knn1.predict(X_test)

print(confusion_matrix(y_test, y_pred_best))
confusion = (confusion_matrix(y_test, y_pred_best))
print("Accuracy for knn:", accuracy_score(y_test, y_pred_best))

TN = confusion[0][0]
FN = confusion[1][0]
TP = confusion[1][1]
FP = confusion[0][1]

accuracy = round((((TP + TN) / (FN + FP + TP + TN)) * 100), 2)
true_pos = round(((TP / (TP + FN)) * 100), 2)
true_neg = round(((TN / (TN + TP)) * 100), 2)
print("Best knn")
print("TP     FP     TN     FN     Accuracy    TPR     TNR")
print(tp, "  ", fp, "  ", tn, "  ", fn, "   ", accuracy, "     ", true_pos, " ",
      true_neg)

# 3_4
# ______________________________________________________________________________
# BU ID 2156

# 4_1
# ______________________________________________________________________________

def knn(xtrain, ytrain, ytest, xtest):
    knn_loop = KNeighborsClassifier(n_neighbors=best_k)
    knn_loop.fit(xtrain, ytrain)

    y_pred_best = knn_loop.predict(xtest)

    confusion_matrix(ytest, y_pred_best)
    confusion = (confusion_matrix(ytest, y_pred_best))
    return (
    "Accuracy for knn:", "{:.2f}".format((accuracy_score(ytest, y_pred_best) * 100)))

banknotes = banknotes.astype(float)
x = banknotes.iloc[:, :-1].values
Y = banknotes.iloc[:, 4].values

X_train, X_test, y_train, y_test = train_test_split(x, Y, test_size=0.50)

X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

# drop f1

X_train1 = np.delete(X_train, 0, 1)

X_test1 = np.delete(X_test, 0, 1)

print("Drop F1")
knn1 = knn(X_train1, y_train, y_test, X_test1)
print(knn1)

# drop f2
X_train2 = np.delete(X_train, 1, 1)

scaler.fit(X_train2)
X_test2 = np.delete(X_test, 1, 1)

print("Drop F2")
knn2 = knn(X_train2, y_train, y_test, X_test2)
print(knn2)

# drop f3
X_train3 = np.delete(X_train, 2, 1)

X_test3 = np.delete(X_test, 2, 1)

print("Drop F3")
print(knn(X_train3, y_train, y_test, X_test3))

# drop f4
X_train4 = np.delete(X_train, 3, 1)

X_test4 = np.delete(X_test, 3, 1)

print("Drop F4")
print(knn(X_train4, y_train, y_test, X_test4))

# 5_1
# ______________________________________________________________________________

banknotes = banknotes.astype(float)
x = banknotes.iloc[:, :-1].values
Y = banknotes.iloc[:, 4].values

X_train, X_test, y_train, y_test = train_test_split(x, Y, test_size=0.50)

logistic_regression = LogisticRegression()

logistic_regression.fit(X_train, y_train)

y_pred_log = logistic_regression.predict(X_test)

accuracy = metrics.accuracy_score(y_test, y_pred_log)
accuracy_percentage = 100 * accuracy
print("Logistic Regression Accuracy: ")
print(accuracy_percentage)

# 5_2
# ______________________________________________________________________________
print(confusion_matrix(y_test, y_pred_log))
confusion = (confusion_matrix(y_test, y_pred_log))

TN = confusion[0][0]
FN = confusion[1][0]
TP = confusion[1][1]
FP = confusion[0][1]

accuracy = round((((TP + TN) / (FN + FP + TP + TN)) * 100), 2)
true_pos = round(((TP / (TP + FN)) * 100), 2)
true_neg = round(((TN / (TN + TP)) * 100), 2)
print("Logistic")
print("TP     FP     TN     FN     Accuracy    TPR     TNR")
print(tp, "  ", fp, "  ", tn, "  ", fn, "   ", accuracy, "     ", true_pos, " ",
      true_neg)

# 6
# ______________________________________________________________________________

def logistic(xtrain, ytrain, ytest, xtest):
    logistic_regression = LogisticRegression()

    logistic_regression.fit(xtrain, ytrain)

    y_pred_log = logistic_regression.predict(xtrain)

    accuracy_loop = metrics.accuracy_score(ytest, y_pred_log)
    accuracy_percentage_loop = 100 * accuracy_loop
    print("Logistic Regression Accuracy: ")
    print(accuracy_percentage_loop)
    print(confusion_matrix(ytest, y_pred_log))
    confusion = (confusion_matrix(ytest, y_pred_log))

    accuracy = round((((TP + TN) / (FN + FP + TP + TN)) * 100), 2)
    true_pos = round(((TP / (TP + FN)) * 100), 2)
    true_neg = round(((TN / (TN + TP)) * 100), 2)

    return("")

# drop f1

X_train1 = np.delete(X_train, 0, 1)

X_test1 = np.delete(X_test, 0, 1)

y_test = np.delete(y_test, -1)
X_test1 = np.delete(X_test1, -1)

print("Drop F1")
print(logistic(X_train1, y_train, y_test, X_test1))
# drop f2
X_train2 = np.delete(X_train, 1, 1)

scaler.fit(X_train2)
X_test2 = np.delete(X_test, 1, 1)

print("Drop F2")
print(logistic(X_train2, y_train, y_test, X_test2))

# drop f3
X_train3 = np.delete(X_train, 2, 1)

X_test3 = np.delete(X_test, 2, 1)

print("Drop F3")
print(logistic(X_train3, y_train, y_test, X_test3))

# drop f4
X_train4 = np.delete(X_train, 3, 1)

X_test4 = np.delete(X_test, 3, 1)

print("Drop F4")
print(logistic(X_train4, y_train, y_test, X_test4))


from moviepy.editor import concatenate_videoclips, VideoFileClip, AudioFileClip, ImageClip, CompositeVideoClip, CompositeAudioClip
from common.metadata_manager import MetadataManager
import pixabay
import os
from common.constants import Constants
import requests
from moviepy.video.fx.all import fadeout
from moviepy.video.compositing.transitions import slide_in, slide_out
import logging
from common.video.audio_generator import AudioGenerator
from utils import Utils
from moviepy.video.io.ffmpeg_reader import FFMPEG_VideoReader
from common.makememe.generator.design.image_manager import Image_Manager
import json
from dotenv import find_dotenv, load_dotenv
from common.video.story_manager import StoryManager
from datetime import datetime
load_dotenv(find_dotenv('../../.env'))
import warnings
import random
import re
from collections import deque
from common.content_generator import ContentGenerator
from clients.midjourney_api import MidjourneyApi
from common.video.video_uploader import upload_video
class VideoGenerator(ContentGenerator):
    def __init__(self, folder_name):
        self.px = pixabay.core(os.getenv("PIXABAY_KEY"))
        self.metadata_manager = MetadataManager()
        self.folder_name = folder_name
        self.story_manager = StoryManager(folder_name)
        self.audio_duration = None
        self.audio_generator = AudioGenerator()

    def script_to_list(self, script):
        sentences = [sentence.strip() for sentence in re.split('([.!?])', script) if sentence.strip()]
        formatted_sentences = ["".join(sentences[i:i+2]) for i in range(0, len(sentences), 2)]
        return formatted_sentences

    def generate_sentence_timestamps(self, script, video_duration):
        sentences = self.script_to_list(script)
        total_words = len(script.split())
        avg_word_duration = video_duration / total_words
        sentence_timestamps = []
        current_time = 0.0
        for sentence in sentences:
            num_words_in_sentence = len(sentence.split())
            sentence_duration = num_words_in_sentence * avg_word_duration
            sentence_timestamps.append((sentence, current_time, current_time + sentence_duration))
            current_time += sentence_duration
        return sentence_timestamps

    def generate_and_download_images(self, sentence_list, num_images=3):
        if os.path.exists(f'{self.folder_name}/images'):
            print(f'images exist at {self.folder_name}/images')
            return
        for i in range(num_images):
            if sentence_list:
                prompt = sentence_list.pop(0)
                midjourney_api = MidjourneyApi(prompt, f"{self.folder_name}/images/image{i}.png")
                midjourney_api.download_image()
            else:
                break

    def getVideo(self, target_length, query):
        path = f'{self.folder_name}/video.mp4'
        print(query)
        if self.metadata_manager.check_metadata(Constants.video, self.folder_name):
            return VideoFileClip(path)
        data = self.get_video_data(query)
        clips, temp_files = self.generate_clips(data, target_length, query)
        final_clip = concatenate_videoclips(clips)
        final_clip.write_videofile(path, codec='libx264')
        for clip in clips:
            clip.close()

        return final_clip

    def get_video_data(self, query):
        url = f'https://pixabay.com/api/videos/?key={os.getenv("PIXABAY_KEY")}&q={query}'
        response = requests.get(url)
        data = {}
        if response.status_code == 200:
            data = response.json()
        else:
            print(f"Request failed with status code {response.status_code}")
        return data

    def generate_clips(self, data, target_length, query):
        clips = []
        temp_files = []
        videos = data["hits"]
        current_length = 0
        num_videos = len(videos)  # Get the total number of videos

        # Create a list of video indices, then shuffle it
        indices = list(range(num_videos))
        random.shuffle(indices)

        for idx in indices:  # Iterate over shuffled indices
            if current_length >= target_length:
                break
            temp_video_path = f'{query}{idx}.mp4'
            Utils.download_file(videos[idx]["videos"]["medium"]["url"], temp_video_path)
            clip, segment_length = self.get_clip_segment(temp_video_path, target_length, current_length)
            clips.append(clip)
            current_length += segment_length
            temp_files.append(temp_video_path)  # Save temp file path

        return clips, temp_files

    def get_clip_segment(self, temp_video_path, target_length, current_length):
        full_clip = VideoFileClip(temp_video_path)
        video_length = full_clip.duration
        max_length = min(7, video_length)
        min_length = min(5, max_length)
        segment_length = random.uniform(min_length, max_length)
        segment_length = min(segment_length, target_length - current_length)
        start_time = random.uniform(0, video_length - segment_length)
        end_time = start_time + segment_length
        clip = full_clip.subclip(start_time, end_time)
        clip = clip.resize(height=1920)  # Resize the height first
        w, h = clip.size
        clip = clip.crop(x_center=w/2, y_center=h/2, width=9*h/16, height=h)  # Crop to 9:16 ratio
        return clip, segment_length

    def build_prompt(self, user_input, scriptLength):
        intro = f"Generate a short, motivational script that offers a positive and encouraging message related to the theme: '{user_input}'.\n\n"
        script_prompt = f"{intro}The script should be short ({scriptLength} seconds). The script should provide an uplifting perspective on common human experiences or feelings, similar to these examples: \n\n 1. 'Struggling to love yourself? Remember, the most powerful relationship you'll ever have is the relationship with yourself. Cherish and nurture it.' \n\n 2. 'Feeling overwhelmed with negativity? Let's turn it around. Find one thing to be grateful for each day, and watch how your perspective changes.' \n\n Please continue in a similar style."

        return script_prompt

    def get_random_music_file(self, folder="music"):
        music_files = os.listdir(folder)  # Lists all files in the directory
        music_files = [f for f in music_files if f.endswith(".mp3")]  # Filter out non-music files
        if not music_files:
            raise Exception("No music files found in directory")
        return os.path.join(folder, random.choice(music_files))  # Picks a random file and returns the path

    def build_thumbnail_prompt(self, audio_prompt):
        purpose = "informative"
        keywords = ["how to", "why", "guide", "tutorial", "strategy", "tips", "methods"]
        prompt = f'Create a catchy and SEO-friendly thumbnail text for a {purpose} YouTube video titled "{audio_prompt}". The text should be short (5 words or less) and could include some of the following keywords: {", ".join(keywords)}.'
        return prompt

    def build_title_prompt(self, script):
        prompt = f'Generate a catchy and inspiring title for a YouTube Shorts video. Keep it short (5 words). The video offers a motivational message about self-improvement and personal growth. The script is {script}'
        return prompt

    def build_description_prompt(self, script):
        prompt = f'Compose a captivating and detailed description for a YouTube Shorts video. Keep it short (15 words). The video is a minute-long motivational clip focusing on the themes of self-love and personal development. The script is {script}'
        return prompt

    def saveText(self, prompt, resource_type):
        script_path = os.path.join(self.folder_name, f'{resource_type}.txt')
        if self.metadata_manager.check_metadata(resource_type, self.folder_name):
            with open(script_path, 'r') as f:
                text = f.read()
            return text
        text = self.generate_text(prompt,500,1)
        os.makedirs(self.folder_name, exist_ok=True)
        with open(os.path.join(self.folder_name, f'{resource_type}.txt'), 'w') as f:
            f.write(text)
        return text

    def generate_thumbnail(self, video_type, audio_prompt):
        logging.info("Creating thumbnail...")
        thumbnail_prompt = self.build_thumbnail_prompt(audio_prompt)
        thumbnail_text = self.saveText(thumbnail_prompt, Constants.thumbnail).replace('"', '')
        Image_Manager.create_thumbnail_with_text(video_type, thumbnail_text, f'{self.folder_name}')

    def generate_script_and_audio(self, audio_prompt):
        logging.info(f"Generating script for {audio_prompt}...")
        prompt = self.build_prompt(audio_prompt)
        script = self.saveText(prompt, Constants.script)
        logging.info("Generating audio...")
        audio_path = self.audio_generator.getBadAudio(script, self.folder_name)
        return script, audio_path

    def get_music(self, duration):
        music_path = self.get_random_music_file()
        music = AudioFileClip(music_path).volumex(0.9)
        latest_start_time = max(0, music.duration - duration)
        start_time = random.uniform(0, latest_start_time)
        music_clip = music.subclip(start_time, start_time + duration)
        return music_clip

    def makeVideo(self):
        DEFAULT_DURATION = 55  # define your constant duration here (in seconds)
        video_output_path = f'{self.folder_name}/videoFinal.mp4'

        # Create directory if it doesn't exist
        os.makedirs(os.path.dirname(video_output_path), exist_ok=True)
        background = random.choice(Constants.cat)
        script = "MAKE_TEXT"
        audio_prompt = random.choice(self.get_topics_from_blog())

        if script == "MAKE_TEXT":
            prompt = self.build_prompt(audio_prompt, DEFAULT_DURATION)
            script = self.saveText(prompt, Constants.script).strip('"')
            sentences = self.script_to_list(script)
            video_clip = self.getVideo(DEFAULT_DURATION, background)

        if script == "CUSTOM_TEXT":
            video_clip = self.getVideo(DEFAULT_DURATION, background)
            music_clip = self.get_music(DEFAULT_DURATION)

            sentences = self.script_to_list(script)

        if script == "MUSIC_ONLY":
            video_clip = self.getVideo(DEFAULT_DURATION + 20, background)
            video_clip = video_clip.set_duration(DEFAULT_DURATION)
            music_clip = self.get_music(DEFAULT_DURATION)
            sentences = []
            durations = []

        video_clip = video_clip.set_audio(CompositeAudioClip([music_clip]))
        durations = self.generate_sentence_timestamps(script, video_clip.duration)
        clips = self.story_manager.get_random_clips(sentences, f'{self.folder_name}/images', durations)
        final_video = self.story_manager.add_clips_to_video([video_clip], clips)

        if script:
            metadata_title = f'{self.generate_text(self.build_title_prompt(script))} #shorts'
            metadata_desc = f'{self.generate_text(self.build_description_prompt(script))} #shorts'
        else:
            metadata_title = f'Inspiring Video with {background} Background #shorts'
            metadata_desc = f'Enjoy this inspiring video featuring a beautiful {background} background. #shorts'

        print(metadata_title)
        print(metadata_desc)

        video_metadata = {
            "snippet": {
                "title": metadata_title.strip('"'),
                "description": metadata_desc.strip('"') ,
                "tags": [],
                "categoryId": "22"  # Category ID for People & Blogs; can be changed according to your need
            },
            "status": {
                "privacyStatus": "unlisted",  # or "public" or "unlisted"
                "selfDeclaredMadeForKids": False,
            }
        }

        if not os.path.exists(f'{self.folder_name}/videoFinal.mp4'):
            final_video.write_videofile(f'{self.folder_name}/videoFinal.mp4', codec='libx264')
        final_video.close()
        upload_video(f'{self.folder_name}/videoFinal.mp4', video_metadata)
        logging.info("Video creation complete!")

def makeVideo():
    # Set up logging
    logging.basicConfig(level=logging.INFO)
    video_data = Utils.load_json("common/video/video_input.json")
    current_date = datetime.now()

    # Convert to string
    datetime_string = current_date.strftime("%Y-%m-%d_%H-%M-%S")
    for category, category_data in video_data.items():
        for i in range(0,3):
            vg = VideoGenerator(f'{Constants.video_file_path}{Utils.sanitize_folder_name(datetime_string)}{i}')
            vg.makeVideo()
    Utils.remove_mp4_files('')


from django.urls import path,include
from .views import  add_order, index,delete_order

urlpatterns = [
    path('',index,name='index'),
    path('add/order/',add_order, name='add_order'),
    path('delete/<int:pk>/',delete_order,name='delete_order'),
    path('__debug__/', include('debug_toolbar.urls')),

]


# -*- coding: utf-8 -*-
"""
Created on Fri Nov  5 14:52:34 2021

@author: manip.batm
"""

import pyvisa
import time
import numpy as np

AWG_SAMPLING_RATE_MHz = 1200

def build_clk(Nclk, clk_rate_MHz):
    # check arguments
    L0 = int(np.round(AWG_SAMPLING_RATE_MHz / (2 * clk_rate_MHz)))
    if L0 < 1:
        raise ValueError("CLK frequency is too high.")
    elif L0 * (2 * clk_rate_MHz) != AWG_SAMPLING_RATE_MHz:
        print(f"CLK frequency rounded to {AWG_SAMPLING_RATE_MHz / (2 * L0)} MHz.")

    # build
    CLK = [0., 0.] + [-1.2, 1.2] * Nclk + [0., 0.]
    CLK = np.tile(CLK, (L0, 1)).flatten("F")
    return CLK, L0

def build_waveforms(values=[0.5]*64, clk_rate_MHz=0.05, data_to_clk_us=5., current_index=63, current_val=0.):
    ## CLK
    CLK, L0 = build_clk(len(values), clk_rate_MHz)
    # addr_change = (np.where(np.diff(CLK) > 0.)[0] + 1).tolist() # indexes of rising CLK edge

    ## DATA - CLK DELAY
    Ldc = int(np.round(data_to_clk_us * AWG_SAMPLING_RATE_MHz))
    if abs(Ldc) >= 2 * L0:
        print("DATA to CLK time is greater than 1 CLK period")
    if Ldc != data_to_clk_us * AWG_SAMPLING_RATE_MHz:
        print(f"DATA to CLK time rounded to {Ldc / AWG_SAMPLING_RATE_MHz} us.")

    ## BUILD WAVEFORMS
    V0 = np.tile(values[::2], (4*L0, 1)).flatten("F")
    V1 = np.tile(values[1::2], (4*L0, 1)).flatten("F")
    if len(values) % 2 == 0:
        V0 = np.concatenate((np.array([V0[0]]*(3 * L0 - Ldc)),
                         V0,
                         np.array([V0[-1]]*(L0 + Ldc)))) # add before and after
        V1 = np.concatenate((np.array([current_val]*(5 * L0 - Ldc)),
                         V1[:-(2 * L0)],
                         np.array([V1[-1]]*(L0 + Ldc)))) # add before and after
    else:
        V0 = np.concatenate((np.array([V0[0]]*(3 * L0 - Ldc)),
                         V0[:-(2 * L0)],
                         np.array([V0[-1]]*(L0 + Ldc)))) # add before and after
        V1 = np.concatenate((np.array([current_val]*(5 * L0 - Ldc)),
                         V1,
                         np.array([V1[-1]]*(L0 + Ldc)))) # add before and after

    # correct for i0 parity
    if current_index % 2 != 0:
        Veven = np.array(V0)
        Vodd = np.array(V1)
    else:
        Vodd = np.array(V1)
        Veven = np.array(V0)

    return Veven, Vodd, CLK

class AWGDriver():
    """
    Driver for Tektronik 5014.
    """
    def __init__(self, AWG_VISA):
        rm = pyvisa.ResourceManager()
        self.instr = rm.open_resource(
            AWG_VISA,
            write_termination="\n",
            read_termination="\n",
        )
        self.chan_ampl = {}
        self.chan_offset = {}
        self.sampling_rate = None
        self.repetition_rate = None
        self.wf_length = None
        self.instr.write("AWGC:RMODE TRIG")
        for c in range(1, 5):
            self.set_amplitude_and_offset(channel=c, amplitude=2.5, offset=0)

    def close(self):
        self.instr.close()

    def wait_opc(self):
        _ = self.instr.query("*OPC?")

    def stop(self):
        self.instr.write("AWGC:STOP")

    def run(self):
        self.instr.write("AWGC:RUN")

    def force_trig(self):
        self.instr.write("*TRG")

    def set_output(self, channel=1, state="OFF"):
        self.instr.write(f"OUTP{channel} {state}")

    def set_all_outputs(self, state="OFF"):
        for k in range(1, 5):
            self.set_output(k, state)

    def set_amplitude_and_offset(self, channel, amplitude=4.5, offset=0.):
        self.chan_ampl[channel] = amplitude
        self.chan_offset[channel] = offset
        self.instr.write(f"SOUR{channel}:VOLT:AMPL {amplitude}")
        self.instr.write(f"SOUR{channel}:VOLT:OFFS {offset}")

    def set_sampling_rate(self, sampl_rate=1.2e9):
        self.sampling_rate = sampl_rate
        if self.wf_length is not None:
            self.repetition_rate = self.sampling_rate / self.wf_length
        self.instr.write(f"SOUR:FREQ {sampl_rate}")

    def set_repetition_rate(self, rep_rate=1e6):
        self.repetition_rate = rep_rate
        if self.wf_length is not None:
            self.sampling_rate = self.repetition_rate * self.wf_length
        self.instr.write(f"AWGC:RRATE {rep_rate}")

    def clear_waveforms(self, name="ALL"):
        self.instr.write(f"WLIST:WAV:DEL {name}")

    def package_wf(self, channel, wf_float, m1, m2):
        ampl = self.chan_ampl[channel]
        offs = self.chan_offset[channel]
        wf_norm = (wf_float - offs) / ampl
        if np.any(np.abs(wf_norm) > 1.):
            raise ValueError(f"Amplitude is too large for channel {channel}")
        else:
            m1 = m1.astype(np.bool)
            m2 = m2.astype(np.bool)
            wf_uint16 = np.uint16(np.round(wf_norm * 8191 + 8191.5)
                                + np.round(16384 * m1)
                                + np.round(32768 * m2))
            return wf_uint16

    def send_and_place_wf(self, channel, wf, m1=None, m2=None):
        # convert waveform to uint16
        if m1 is None:
            m1 = np.zeros(wf.shape, dtype=np.bool)
        if m2 is None:
            m2 = np.zeros(wf.shape, dtype=np.bool)
        wf_uint16 = self.package_wf(channel, wf, m1, m2)

        # update repetition rate
        self.wf_length = len(wf_uint16)
        if self.sampling_rate is not None:
            self.repetition_rate = self.sampling_rate / self.wf_length
        elif self.repetition_rate is not None:
            self.sampling_rate = self.repetition_rate / self.wf_length

        # transfer wf
        wfm_name = f"CH{channel}_wfm"
        self.instr.write(f"WLIST:WAV:DEL \"{wfm_name}\"") # delete waveform if existing
        self.instr.write(f"WLIST:WAV:NEW \"{wfm_name}\", {len(wf_uint16)}, INT") # create empty wf
        self.instr.write_binary_values(f"WLIST:WAV:DATA \"{wfm_name}\", ", wf_uint16, datatype="h") # transfer binary data
        self.instr.write(f"SOUR{channel}:WAV \"{wfm_name}\"") # set waveform as active

if __name__=="__main__":

    # runfile("follow_selected_AWG.py")

    AWG_VISA = "TCPIP::192.168.1.12::4000::SOCKET"
    awg = AWGDriver(AWG_VISA)

    # config
    # awg.set_sampling_rate(sampl_rate=1.2e9)
    awg.set_repetition_rate(rep_rate=1e6)

    sine = np.sin(np.linspace(0, 6, 601) * np.pi)
    awg.send_and_place_wf(channel=1, wf=sine, m1=None, m2=None)
    awg.send_and_place_wf(channel=2, wf=-sine, m1=None, m2=None)
    awg.send_and_place_wf(channel=3, wf=sine, m1=None, m2=None)
    awg.send_and_place_wf(channel=4, wf=-sine, m1=None, m2=None)

    # close instrument
    awg.close()


import cv2
import numpy as np
import os
path ='./female_large_pose_process_new/anran_dance/imgs/000050.jpg'
img = cv2.imread(path).astype(np.float)/255

parsing_mask = np.load('./female_large_pose_process_new/anran_dance/parsing_SCH_ATR/mask_parsing_000050.npy')
upper_idx = [1, 2, 3, 4,5,8,  11, 16, 17, 14, 15]

foreground = np.zeros(img.shape).astype(np.bool)

for idx in upper_idx:
    foreground |= (parsing_mask == 20)[..., None]

foreground = foreground.astype(np.float)
for ratio in range(1,10):
    alpha = ratio/10.
    pre_img = foreground * img + (1-foreground) * (img * alpha + 1 *(1-alpha))
    pre_img = (255*pre_img).astype(np.uint8)

    print('./pipeline_graph_curve/{:.4f}.png'.format(alpha))
    cv2.imwrite('./pipeline_graph_curve/{:.4f}.png'.format(alpha), pre_img)


"""
Indivo Views -- HealthActionOccurrence
"""

from django.http import HttpResponseBadRequest, HttpResponse
from indivo.lib.view_decorators import marsloader, DEFAULT_ORDERBY
from indivo.lib.query import FactQuery, DATE, STRING, NUMBER
from indivo.models import HealthActionOccurrence

HEALTHACTIONOCCURRENCE_FILTERS = {
    DEFAULT_ORDERBY : ('created_at', DATE),
    'name': ('name', STRING),
    'name_type' : ('name_type', STRING),
    'name_value' : ('name_value', STRING),
    'name_abbrev' : ('name_abbrerv', STRING),
    'recurrenceIndex': ('recurrenceIndex', NUMBER)
}

HEALTHACTIONOCCURRENCE_TEMPLATE = 'reports/healthactionoccurrence.xml'

def healthactionoccurrence_list(*args, **kwargs):
    """For 1:1 mapping of URLs to views. Calls _healthactionoccurrence_list"""
    return _healthactionoccurrence_list(*args, **kwargs)

def carenet_healthactionoccurrence_list(*args, **kwargs):
    """For 1:1 mapping of URLs to views. Calls _healthactionoccurrence_list"""
    return _healthactionoccurrence_list(*args, **kwargs)

@marsloader(query_api_support=True)
def _healthactionoccurrence_list(request, group_by, date_group, aggregate_by,
                                 limit, offset, order_by,
                                 status, date_range, filters,
                                 record=None, carenet=None):
    q = FactQuery(HealthActionOccurrence, HEALTHACTIONOCCURRENCE_FILTERS,
                  group_by, date_group, aggregate_by,
                  limit, offset, order_by,
                  status, date_range, filters,
                  record, carenet)
    try:
        return q.render(HEALTHACTIONOCCURRENCE_TEMPLATE)
    except ValueError as e:
        return HttpResponseBadRequest(str(e))


import ctypes as _ctypes
from typing import Any, List, Union, Optional

from .types import *

if IS_WIN:
    from . import _nt as _nt
from . import mem as _mem

__all__ = ["MemoryRegion", "MemScanner"]

class MemoryRegion:
    def __init__(
        self, allocation_base: LPVOID, base_address: LPVOID, region_size: SIZE_T
    ):
        self.allocation_base: LPVOID = allocation_base
        self.base_address: LPVOID = base_address
        self.region_size: SIZE_T = region_size
        self.dumped_region: Optional[_ctypes.Array] = None

    def __str__(self):
        return "%s(%s)" % (
            type(self).__name__,
            ", ".join("%s=%s" % item for item in vars(self).items()),
        )

    def __repr__(self):
        return self.__str__()

def _check_mask(memory: _ctypes.Array, offset: int, pattern: bytes, mask: str) -> bool:
    if offset + len(pattern) > len(memory):
        return False
    for i in range(len(pattern)):
        if mask[i] == "?":
            continue
        if pattern[i] != memory[offset + i]:
            return False
    return True

class MemScanner:
    def __init__(self, process: Union[int, str]):
        self._region_list: List[MemoryRegion] = []
        if process == 0:
            raise RuntimeError("Invalid handle.")
        self._pid: int = process if isinstance(process, int) else _mem.get_pid(process)
        if IS_WIN:
            self._handle = _nt.open_process(self._pid)
            self._sysinfo = _nt.SYSINFO
        self._init_region_list()

    def _init_region_list(self) -> None:
        handle = _nt.open_process(self._pid)
        current_addr: int = _nt.SYSINFO.MinimumApplicationAddress
        proc_max_addr: int = _nt.SYSINFO.MaximumApplicationAddress
        while current_addr < proc_max_addr:
            mem_info = _nt.query_mem_info(handle, LPCVOID(current_addr))
            if (
                mem_info.Protect & _nt.AllocationProtect.PAGE_EXECUTE_READWRITE > 0
                and mem_info.State == _nt.MEM_COMMIT
            ):
                region = MemoryRegion(
                    LPVOID(mem_info.AllocationBase),
                    LPVOID(mem_info.BaseAddress),
                    SIZE_T(mem_info.RegionSize),
                )
                self._region_list.append(region)
            current_addr += mem_info.RegionSize
        _nt.close_handle(handle)

    def _dump_memory(self) -> bool:
        for region in self._region_list:
            if region.dumped_region is None:
                region.dumped_region = _ctypes.create_string_buffer(
                    region.region_size.value
                )
            read_size = _nt.read_proc_mem(
                self._handle,
                region.base_address,
                region.dumped_region,
                region.region_size,
            )
            if read_size.value != region.region_size.value:
                return False
        return True

    def search_pattern(
        self, pattern: Union[str, bytes], mask: Optional[str] = None
    ) -> int:
        """
        Searches for the pattern in the memory of the process.

        Parameters
        ----------
        pattern:
            If given as a string, the format will be like
                5A 0F 3C ?? 5D 9A 4B
            where ?? matches any byte and space can be omitted.
            If given as a byte array, the format will be like
                \\x5a\\x0f\\x3c\\x00\\x5d\\x9a\\x4b
            and if wildcard is needed, you should use the `mask` parameter.

        mask:
            If given, then the format will be like
                xxx?xxx
            where ? is the position of the byte to match any byte.

        Returns
        -------
        The starting location of the matched memory section. If not found, then 0 is returned.
        """
        if isinstance(pattern, str):
            pattern = pattern.replace(" ", "")
            if mask is None:
                mask = ""
                for i in range(0, len(pattern), 2):
                    mask += "?" if pattern[i : i + 2] == "??" else "x"
            pattern = pattern.replace("??", "00")
            pattern = bytes.fromhex(pattern)
        if not self._dump_memory():
            return 0
        assert mask is not None
        for region in self._region_list:
            assert region.dumped_region is not None
            assert region.base_address.value is not None
            for i in range(len(region.dumped_region)):
                if _check_mask(region.dumped_region, i, pattern, mask):
                    return region.base_address.value + i
        return 0

    def read_mem(self, base_addr: int, size: int) -> bytes:
        return _mem.read_mem(self._handle, base_addr, size)

    @property
    def region_list(self) -> List[MemoryRegion]:
        if not self._dump_memory():
            raise RuntimeError("Unable to dump memory")
        return self._region_list

    def close(self) -> None:
        _nt.close_handle(self._handle)

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.close()
        return


from django.contrib.auth.models import Group
from django.db import models

class Plan(models.Model):
    BASIC = 1
    PRO = 2
    AGENCY = 3
    ID_CHOICES = [
        (BASIC, "Basic"),
        (PRO, "Pro"),
        (AGENCY, "Agency"),
    ]

    id = models.PositiveSmallIntegerField(choices=ID_CHOICES, primary_key=True)
    group = models.OneToOneField(Group, on_delete=models.CASCADE)

    # settings
    RECRAWL_DAILY = 1
    RECRAWL_WEEKLY = 2
    RECRAWL_CHOICES = [
        (RECRAWL_DAILY, "Daily"),
        (RECRAWL_WEEKLY, "Weekly"),
    ]

    max_sites = models.IntegerField(default=10)
    recrawl_schedule = models.CharField(
        max_length=63,
        default="0 18 * * 0",
        help_text="cron format",
    )
    recrawl_frequency = models.PositiveSmallIntegerField(choices=RECRAWL_CHOICES, null=False, default=RECRAWL_WEEKLY)
    uptime_schedule = models.CharField(
        max_length=63,
        default="0 * * * *",
        help_text="cron format",
    )

    def __str__(self):
        return self.get_id_display()


from django.shortcuts import render, get_object_or_404
from django.http import Http404

# Create your views here.
from .models import BlogPost
from .forms import BlogPostModelForm
#
# def blog_post_detail_page(request, slug):
#     # queryset = BlogPost.objects.filter(slug=slug)  # query->data base->data->django render it
#     # if queryset.count() ==0:
#     #     raise Http404
#     # obj = queryset.first()
#     obj = get_object_or_404(BlogPost, slug=slug)
#     template_name = "blog_post_detail.html"
#     context = {"object": obj}
#     return render(request, template_name, context)

def blog_post_list_view(request):
    qs = BlogPost.objects.all()  #queryset-> list of python objects
    context = {"object_list": qs}
    template_name = "blog/list.html"
    return render(request, template_name, context)

def blog_post_create_view(request):
    # for creating objects we need using a form
    form = BlogPostModelForm(request.POST or None)
    if form.is_valid():
        print(form.cleaned_data)
        # obj = BlogPostModelForm.objects.create(**form.cleaned_data)
        obj = form.save(commit=False)
        obj.save()
        form= BlogPostModelForm()
    context = {"form": form}
    template_name = "form.html"
    return render(request, template_name, context)

def blog_post_detail_view(request, slug):
    # this is 1 object->detail view
    obj = get_object_or_404(BlogPost, slug=slug)
    context = {"object": obj}
    template_name = "blog/detail.html"
    return render(request, template_name, context)

def blog_post_update_view(request,slug):
    # this is 1 object
    obj = get_object_or_404(BlogPost, slug=slug)
    context = {"object": obj, "form": None}
    template_name = "blog/update.html"
    return render(request, template_name, context)

def blog_post_delete_view(request, slug):
    # this is 1 object
    obj = get_object_or_404(BlogPost, slug=slug)
    context = {"object": obj}
    template_name = "blog/delete.html"
    return render(request, template_name, context)


"""EDI raw import tests"""

from base64 import b64encode, b64decode
import re
from .common import EdiCase

class TestRaw(EdiCase):
    """EDI raw import tests"""

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.doc_type_raw = cls.env.ref('edi.raw_document_type')

    def create_raw(self, *filenames):
        """Create raw import document(s)"""
        EdiDocumentType = self.env['edi.document.type']
        attachments = self.create_attachment(*filenames)
        docs = EdiDocumentType.autocreate(attachments)
        self.assertEqual(len(docs), len(filenames))
        self.assertEqual(docs.mapped('doc_type_id'), self.doc_type_raw)
        self.assertEqual(docs.mapped('input_ids'), attachments)
        return docs

    def test01_basic(self):
        """Basic execution"""
        User = self.env['res.users']
        doc = self.create_raw('res.users.csv')
        self.assertTrue(doc.action_execute())
        recs = doc.raw_ids
        self.assertEqual(len(recs), 3)
        for rec in recs:
            self.assertEqual(rec.model_id.model, 'res.users')
        users = User.browse([x.res_id for x in recs])
        users_by_login = {x.login: x for x in users}
        self.assertEqual(users_by_login['alice'].name, "Alice")
        self.assertEqual(users_by_login['bob'].name, "Bob")
        eve = users_by_login['eve']
        self.assertEqual(eve, self.env.ref('__import__.user_eve'))
        self.assertEqual(self.env[eve.action_id.type].browse(eve.action_id.id),
                         self.env.ref('mail.action_view_mail_message'))
        self.assertEqual(doc.raw_count, 3)
        action = doc.action_view_raw()
        self.assertEqual(
            self.env[action['res_model']].search(action['domain']),
            users
        )

    def test02_unknown_format(self):
        """Unknown file format"""
        doc = self.create_raw('res.users.csv')
        doc.input_ids.datas_fname = 'res.users.garbage'
        with self.assertRaisesIssue(doc):
            doc.action_prepare()

    def test03_unknown_field(self):
        """Unknown field in header row"""
        doc = self.create_raw('res.users.csv')
        attachment = doc.input_ids
        attachment.datas = b64encode(re.sub(
            b'login', b'not_the_login_field',
            b64decode(attachment.datas)
        ))
        with self.assertRaisesIssue(doc):
            doc.action_prepare()

    def test04_invalid_xmlid(self):
        """Invalid value"""
        doc = self.create_raw('res.users.csv')
        attachment = doc.input_ids
        attachment.datas = b64encode(re.sub(
            b'mail.action_view_mail_message', b'edi.nonexistent_xmlid',
            b64decode(attachment.datas)
        ))
        with self.assertRaisesIssue(doc):
            doc.action_execute()

    def test05_prefixed_filename(self):
        """Prefixed model name in filename"""
        doc = self.create_raw('res.users.csv')
        attachment = doc.input_ids
        attachment.datas_fname = '01-initial-res.users.csv'
        self.assertTrue(doc.action_execute())

    def test06_unknown_model(self):
        """Unrecognised model name in filename"""
        doc = self.create_raw('res.users.csv')
        attachment = doc.input_ids
        attachment.datas_fname = '01-initial-res.definitely.not.users.csv'
        with self.assertRaisesIssue(doc):
            doc.action_prepare()

    def test07_unrecognisable_filename(self):
        """Unrecognisable model name in filename"""
        doc = self.create_raw('res.users.csv')
        attachment = doc.input_ids
        attachment.datas_fname = 'res.users-broken.csv'
        with self.assertRaisesIssue(doc):
            doc.action_prepare()


from collections import deque

class Solution:
    def removeStars(self, s: str) -> str:
        res = deque()
        skip = 0

        for i in range(len(s) - 1, -1, -1):
            char = s[i]

            if char == "*":
                skip += 1
            elif skip > 0:
                skip -= 1
            else:
                res.appendleft(char)

        return "".join(res)


from __future__ import unicode_literals
from csv import writer
from inspect import getfile
from unicodedata import name
import frappe
from frappe.utils import cstr, add_days, date_diff, getdate
from frappe import _
from frappe.utils.csvutils import UnicodeWriter, read_csv_content
from frappe.utils.file_manager import get_file, upload
from frappe.model.document import Document
from datetime import datetime,timedelta,date,time
from frappe.utils import cint,today,flt,date_diff,add_days,add_months,date_diff,getdate,formatdate,cint,cstr
from numpy import unicode_
from frappe.utils.background_jobs import enqueue

class BulkUploadShiftSchedule(Document):

    def on_submit(self):
        shift = self.name
        frappe.log_error('Shift scheduele')
        enqueue(self.create_shift_assignment, queue='default', timeout=6000, event='create_shift_assignment',shift=shift)

    # def enqueue_submit_schedule(self,docstatus,shift):
    #     if docstatus == "Approved":
    #         shift_assigned = frappe.get_all("Shift Assignment",{'shift_schedule':self.name,'docstatus':'0'})
    #         for shift in shift_assigned:
    #             doc = frappe.get_doc('Shift Assignment',shift.name)
    #             doc.submit()
    #             frappe.db.commit()
    #         frappe.msgprint('Shift Schedule Approved Successfully')

    #     elif docstatus == 'Rejected':
    #         shift_reject = frappe.db.get_all('Shift Assignment',{'shift_schedule':self.name,'docstatus':'0'})
    #         for shift in shift_reject:
    #             frappe.errprint(shift.name)
    #             frappe.delete_doc('Shift Assignment',shift.name)
    #         frappe.msgprint('Shift Schedule Rejected Successfully')

    # def validate(self):
    #     enqueue(self.create_shift_assignment, queue='default', timeout=6000, event='create_shift_assignment')

    def create_shift_assignment(self,shift):
        filepath = get_file(self.attach)
        pps = read_csv_content(filepath[1])
        dates = self.get_dates()
        for date in dates:
            for pp in pps:
                if pp[2] != 'Shift':
                    if pp[1]:
                        get_shift = frappe.db.exists("Shift Assignment",{'employee':pp[0],'start_date':date,'end_date':date,'docstatus':['in',[0,1]]})
                        if not get_shift:
                            doc = frappe.new_doc('Shift Assignment')
                            doc.employee = pp[0]
                            doc.shift_type = pp[2]
                            doc.department = pp[3]
                            doc.start_date = date
                            doc.end_date = date
                            doc.bulk_upload_shift = self.name
                            doc.save(ignore_permissions=True)
                            doc.submit()
                            frappe.db.commit()
                        else:
                            frappe.db.set_value('Shift Assignment',get_shift,'shift_type',pp[2])

    def get_dates(self):
        no_of_days = date_diff(add_days(self.to_date, 1), self.from_date)
        dates = [add_days(self.from_date, i) for i in range(0, no_of_days)]
        return dates

@frappe.whitelist()
def get_template(from_date):
    args = frappe.local.form_dict

    if getdate(args.from_date) > getdate(args.to_date):
        frappe.throw(_("To Date should be greater than From Date"))

    w = UnicodeWriter()
    w = add_header(w)
    w = add_data(w, args,from_date)

    frappe.response['result'] = cstr(w.getvalue())
    frappe.response['type'] = 'csv'
    frappe.response['doctype'] = "Shift Assignment"

def add_header(w):
    w.writerow(['Employee ID','Employee Name','Shift','Department','Department Line'])
    return w

def add_data(w, args,from_date):
    data = get_data(args,from_date)
    writedata(w, data)
    return w

@frappe.whitelist()
def get_data(args,from_date):
    employees = frappe.get_all('Employee',{'status':'Active','department':args.department},['*'])
    data = []
    for emp in employees:
        previous_day = add_days(from_date,-2)
        shift = frappe.db.get_value('Shift Assignment',{'employee':emp.employee_number,'start_date':previous_day},['shift_type'])
        if shift:
            row = [emp.name,emp.employee_name,shift,emp.department,emp.department_line]
            data.append(row)
        else:
            row = [emp.name,emp.employee_name,'G',emp.department,emp.department_line]
            data.append(row)
    return data

@frappe.whitelist()
def writedata(w, data):
    for row in data:
        w.writerow(row)


import json
import jsonschema
import sys
from os import path

sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from preprocessing import create_new_instrument

# This script aggregates the four ADOS modules item by item into an "ADOS" instrument. I only combine items
# if they have identical or very similar descriptions. I also retain all items, even if they don't
# merge across modules. This means we don't lose very much information between any given module and the
# aggregated ADOS instrument.

# This code requires aggregate_phenotype.py to already have been run.
# It outputs a file called all_samples_stage2.json which contains a new ADOS instrument for all
# samples with any of the four ADOS modules.
# It is meant to be run as part of a multi-stage pipeline described in the README.

# The code can be run with:
# python3 aggregate_ados.py

with open(sys.argv[1], 'r') as infile:
	samples = json.load(infile)

with open("AutismPhenotype.json") as schema_file:
	pheno_schema = json.load(schema_file)

feature_mapping = {
	'ADOS_Module1': {
		"QA01": "QA01", "QA02": "QA11", "QA03": "QA02", "QA04": "QA03", "QA05": "QA04",
		"QA06": "QA12", "QA07": "QA07", "QA08": "QA10",
		"QB01": "QB01", "QB02": "QB17", "QB03": "QB02", "QB04": "QB16", "QB05": "QB04",
		"QB06": "QB07", "QB07": "QB19", "QB08": "QB21", "QB09": "QB08", "QB10": "QB10",
		"QB11": "QB09", "QB12": "QB13", "QB13.1": "QB11", "QB13.2": "QB23", "QB14": "QB14", "QB15": "QB22",
		"QB16": "QB15",
		"QC01": "QC01", "QC02": "QC02",
		"QD01": "QD01", "QD02": "QD02", "QD03": "QD03", "QD04": "QD04",
		"QE01": "QE01", "QE02": "QE02", "QE03": "QE03"
	},
	'ADOS_Module2': {
		"QA01": "QA01", "QA02": "QA02", "QA03": "QA03", "QA04": "QA04", "QA05": "QA09",
		"QA06": "QA07", "QA07": "QA10",
		"QB01": "QB01", "QB02": "QB02", "QB03": "QB04", "QB04": "QB07", "QB05": "QB08",
		"QB06": "QB10", "QB07": "QB09", "QB08": "QB13", "QB09.1": "QB11", "QB09.2": "QB23", "QB10": "QB14",
		"QB11": "QB12", "QB12": "QB15",
		"QC01": "QC01", "QC02": "QC02",
		"QD01": "QD01", "QD02": "QD02", "QD03": "QD03", "QD04": "QD04",
		"QE01": "QE01", "QE02": "QE02", "QE03": "QE03"
	},
	'ADOS_Module3': {
		"QA01": "QA01", "QA02": "QA02", "QA03": "QA03", "QA04": "QA04", "QA05": "QA05",
		"QA06": "QA06", "QA07": "QA08", "QA08": "QA09", "QA09": "QA10",
		"QB01": "QB01", "QB02": "QB02", "QB03": "QB03", "QB04": "QB04", "QB05": "QB05",
		"QB06": "QB06", "QB07": "QB13", "QB08": "QB11", "QB09": "QB14", "QB10": "QB12",
		"QB11": "QB15",
		"QC01": "QC02",
		"QD01": "QD01", "QD02": "QD02", "QD03": "QD03", "QD04": "QD04", "QD05": "QD05",
		"QE01": "QE01", "QE02": "QE02", "QE03": "QE03"

	},
	'ADOS_Module4': {
		"QA01": "QA01", "QA02": "QA02", "QA03": "QA03", "QA04": "QA04", "QA05": "QA05",
		"QA06": "QA06", "QA07": "QA08", "QA08": "QA09", "QA09": "QA10", "QA10": "QA13",
		"QB01": "QB01", "QB02": "QB02", "QB03": "QB03", "QB04": "QB04", "QB05": "QB18",
		"QB06": "QB05", "QB07": "QB06", "QB08": "QB20", "QB09": "QB13", "QB10": "QB11",
		"QB11": "QB14", "QB12": "QB12", "QB13": "QB15",
		"QC01": "QC02",
		"QD01": "QD01", "QD02": "QD02", "QD03": "QD03", "QD04": "QD04", "QD05": "QD05",
		"QE01": "QE01", "QE02": "QE02", "QE03": "QE03"
	}
}

ados_instruments = ['ADOS_Module1', 'ADOS_Module2', 'ADOS_Module3', 'ADOS_Module4']

if __name__ == '__main__':
	for sample in samples:
		ados_found = False
		for instrument in ados_instruments:
			if not ados_found and instrument in sample:
				ados_found = True

				# Construct an ados instrument
				sample['ADOS'] = create_new_instrument('ADOS', pheno_schema)
				sample['ADOS']['module'] = instrument

				#Map values
				for key, value in sample[instrument].items():
					if key in feature_mapping[instrument]:
						sample['ADOS'][feature_mapping[instrument][key]] = value
					elif key in sample['ADOS']:
						sample['ADOS'][key] = value

		jsonschema.validate(sample, pheno_schema)

	# Write json to file
	with open(sys.argv[2], 'w+') as outfile:
		print(len(samples))
		json.dump(samples, outfile, sort_keys=True, indent=4)


"""Miscellaneous file utility functions."""

import logging
import os
import errno

LOGGER = logging.getLogger(__name__)

def create_file(path):
    """
    Check if a file exists.

    If it does not, creates an empty file with the given path. Will create directories that don't
    exist in the path.

    :param path: The path to create.
    :raises OSError: This shouldn't happen, but unexpected OSErrors will get raised (we catch
        EEXist already).
    :returns: ``None``.
    """
    LOGGER.debug('Creating new file: {}'.format(path))
    if not os.path.exists(path):
        # Make directory
        try:
            os.makedirs(os.path.dirname(path))
        except OSError as err:
            if err.errno == errno.EEXIST:
                msg = ('Directory already created, or race condition? Check '
                       'path: {}'.format(path))
                LOGGER.error(msg)
            else:
                msg = 'Unexpected OSError: {}'.format(err)
                LOGGER.error(msg)
                raise OSError(msg)
        # Make file
        with open(path, 'a+') as f:
            f.close()


from apscheduler.schedulers.background import BackgroundScheduler
from core.models import RegisteredAssets
from core.utils import update_asset_price

def start():
    scheduler = BackgroundScheduler()

    for asset in RegisteredAssets.objects.all():

        scheduler.add_job(update_asset_price, 'interval', days=asset.frequency, args=[asset])

    scheduler.start()

def create(asset):
    scheduler = BackgroundScheduler()
    scheduler.add_job(update_asset_price, 'interval', days=asset.frequency, args=[asset])
    scheduler.start()


import os

import cv2
import numpy as np
import paddle
import tqdm

from paddleseg.utils import ConfusionMatrix, Timer, calculate_eta, logger

np.set_printoptions(suppress=True)

def evaluate(model, eval_dataset=None, iter_id=None):
    model.eval()

    total_iters = len(eval_dataset)
    conf_mat = ConfusionMatrix(eval_dataset.num_classes, streaming=True)

    logger.info("Start evaluating (total_samples={}, total_iters={})...".format(
        len(eval_dataset), total_iters))
    timer = Timer()
    timer.start()
    for iter, (im, im_info, label) in tqdm.tqdm(
            enumerate(eval_dataset), total=total_iters):
        im = paddle.to_tensor(im)
        logits = model(im)
        pred = paddle.argmax(logits[0], axis=1)
        pred = pred.numpy().astype('float32')
        pred = np.squeeze(pred)
        for info in im_info[::-1]:
            if info[0] == 'resize':
                h, w = info[1][0], info[1][1]
                pred = cv2.resize(pred, (w, h), cv2.INTER_NEAREST)
            elif info[0] == 'padding':
                h, w = info[1][0], info[1][1]
                pred = pred[0:h, 0:w]
            else:
                raise ValueError("Unexpected info '{}' in im_info".format(
                    info[0]))
        pred = pred[np.newaxis, :, :, np.newaxis]
        pred = pred.astype('int64')
        mask = label != eval_dataset.ignore_index
        # To-DO Test Execution Time
        conf_mat.calculate(pred=pred, label=label, mask=mask)
        _, iou = conf_mat.mean_iou()

        time_iter = timer.elapsed_time()
        remain_iter = total_iters - iter - 1
        logger.debug(
            "[EVAL] iter_id={}, iter={}/{}, IoU={:4f}, sec/iter={:.4f} | ETA {}"
            .format(iter_id, iter + 1, total_iters, iou, time_iter,
                    calculate_eta(remain_iter, time_iter)))
        timer.restart()

    class_iou, miou = conf_mat.mean_iou()
    class_acc, acc = conf_mat.accuracy()
    logger.info("[EVAL] #Images={} mIoU={:.4f} Acc={:.4f} Kappa={:.4f} ".format(
        len(eval_dataset), miou, acc, conf_mat.kappa()))
    logger.info("[EVAL] Class IoU: \n" + str(np.round(class_iou, 4)))
    logger.info("[EVAL] Class Acc: \n" + str(np.round(class_acc, 4)))
    return miou, acc


import numpy as np
import cv2
from matplotlib.backends.backend_agg import FigureCanvas
import random
from gym import Env, spaces, GoalEnv
from InsectGym.Voronoi.voronoi_maze import VoronoiMaze
from InsectGym.Voronoi.voronoi_maze_plots import VoronoiMazePlot
from InsectGym.Voronoi.VoronoiWorld import VoronoiWorld, Robot
font = cv2.FONT_HERSHEY_COMPLEX_SMALL

class VoronoiWorldGoal(VoronoiWorld, GoalEnv):
    def __init__(self, colors_dict=None, multi_route_prob=0.1, plot_path=None, task_path=None,
                 random_start=False, num_goals=1):
        # super(VoronoiWorldTarget, self).__init__(colors_dict=colors_dict, multi_route_prob=multi_route_prob)
        self.random_start = random_start
        super(VoronoiWorldGoal, self).__init__(colors_dict=colors_dict, multi_route_prob=multi_route_prob,
                                               plot_path=plot_path, task_path=task_path, num_exits=num_goals)
        # self.width = 100
        # self.height = 100
        # self.maze = VoronoiMaze(width=self.width, height=self.height, multi_route_prob=multi_route_prob)
        # self.locations = np.array(self.maze.voronoi.points)
        # print("max_viable_neighbours = %d" % self.maze.max_viable_neighbours)
        # if not colors_dict:
        #     self.colors_dict = {
        #         "background_color": "#e0e0e0",
        #         "maze_line_color": "navy",
        #         "neighbor_line_color": "orange",
        #         "point_color": "orange",
        #         "start_color": "blue",
        #         "exit_color": "green",
        #         "polygon_face_color": "#1fc600",
        #         "polygon_edge_color": "none",
        #         "polygon_backtracking_color": "purple",
        #         "polygon_backtracking_edge_color": "none"
        #     }
        # else:
        #     self.colors_dict = colors_dict

        # # Define a 2-D observation space
        # self.observation_shape = (1,)
        # self.observation_space = spaces.Discrete(len(self.maze.voronoi.points))
        self.observation_space = spaces.Dict(dict(
            desired_goal=spaces.Discrete(len(self.maze.voronoi.points)),
            achieved_goal=spaces.Discrete(len(self.maze.voronoi.points)),
            observation=spaces.Discrete(len(self.maze.voronoi.points)),
        ))
        # # Define an action space according to self.maze.max_viable_neighbours
        # self.action_space = spaces.Discrete(self.maze.max_viable_neighbours, )
        #
        # self.number_of_locations = len(self.locations)
        # self.init_plot_on_canvas()
        # self.reset()

    def step(self, action):
        # Flag that marks the termination of an episode
        done = False

        # Assert that it is a valid action
        assert self.action_space.contains(action), "Invalid Action"

        # apply the action to the robot
        if len(self.maze.path_graph[self.robot.location]) > action:
            new_location = self.maze.path_graph[self.robot.location][action]
            location_index = self.coordinate_to_index(new_location)
            self.robot.move_to(new_location, location_index)
        else:
            self.reward -= 0  # no punishment to hit the wall for now.
        self.robot.cost()
        # If out of fuel, end the episode.
        if self.robot.fuel_left == 0:
            done = True
        if np.any(self.robot.location_index == self.goal_location_index):
            done = True
        obs = {
            'observation': self.robot.location_index,
            'achieved_goal': self.robot.location_index,
            'desired_goal': self.goal_location_index
        }
        state = {'robot_location': self.robot.location, 'goal_location': self.goal_location, 'actual_action':action}
        self.reward = self.compute_reward(self.robot.location_index, self.goal_location_index, state)
        return obs, self.reward, done, state

    def compute_reward(self, achieved_goal, desired_goal, info):
        # Reward for executing a step.
        reward = -1
        if len(self.maze.path_graph[info['robot_location']]) <= info['actual_action']:
            self.reward -= 0  # no punishment to hit the wall for now.
        if np.any(achieved_goal == desired_goal):
            reward += 20
        return reward

    def reset(self):
        if self.random_start:
            self.start_location_index = random.choice(range(self.number_of_locations))
        else:
            if hasattr(self, 'goal_location_index'):
                self.start_location_index = self.robot.location_index
            else:
                self.start_location_index = random.choice(range(self.number_of_locations))
        self.robot = Robot(location=self.index_to_coordinate(self.start_location_index),
                           location_index=self.start_location_index)

        self.goal_location_index = np.random.choice(len(self.locations), self.num_exits).tolist()
        if self.num_exits == 1:
            self.goal_location_index = self.goal_location_index[0]
        self.goal_location = self.index_to_coordinate(self.goal_location_index)
        self.reward = 0
        self.init_enter_exit_on_canvas()
        self.draw_location_on_canvas()
        # return the observation
        obs = {
            'observation': self.robot.location_index,
            'achieved_goal': self.robot.location_index,
            'desired_goal': self.goal_location_index,
        }
        print(obs)
        return obs

if __name__ == "__main__":
    env = VoronoiWorldGoal(num_goals=2)
    obs = env.reset()
    while True:
        # Take a random action
        action = env.action_space.sample()
        obs, reward, done, info = env.step(action)

        # Render the game
        env.render()

        if done:
            break

    env.close()


# Author: Tomas Hodan (hodantom@cmp.felk.cvut.cz)
# Center for Machine Perception, Czech Technical University in Prague

# Implementation of the pose error functions described in:
# Hodan et al., "On Evaluation of 6D Object Pose Estimation", ECCVW 2016

import math
import numpy as np
from scipy import spatial
from transforms3d.quaternions import quat2mat, mat2quat
import cv2
#from .hodan_renderer import render

def estimate_visib_mask(d_test, d_model, delta):
    """
    Estimation of visibility mask.
    :param d_test: Distance image of the test scene.
    :param d_model: Rendered distance image of the object model.
    :param delta: Tolerance used in the visibility test.
    :return: Visibility mask.
    """
    assert(d_test.shape == d_model.shape)
    mask_valid = np.logical_and(d_test > 0, d_model > 0)

    d_diff = d_model.astype(np.float32) - d_test.astype(np.float32)
    visib_mask = np.logical_and(d_diff <= delta, mask_valid)

    return visib_mask

def estimate_visib_mask_gt(d_test, d_gt, delta):
    visib_gt = estimate_visib_mask(d_test, d_gt, delta)
    return visib_gt

def estimate_visib_mask_est(d_test, d_est, visib_gt, delta):
    visib_est = estimate_visib_mask(d_test, d_est, delta)
    visib_est = np.logical_or(visib_est, np.logical_and(visib_gt, d_est > 0))
    return visib_est

def depth_im_to_dist_im(depth_im, K):
    """
    Converts depth image to distance image.
    :param depth_im: Input depth image, where depth_im[y, x] is the Z coordinate
    of the 3D point [X, Y, Z] that projects to pixel [x, y], or 0 if there is
    no such 3D point (this is a typical output of the Kinect-like sensors).
    :param K: Camera matrix.
    :return: Distance image dist_im, where dist_im[y, x] is the distance from
    the camera center to the 3D point [X, Y, Z] that projects to pixel [x, y],
    or 0 if there is no such 3D point.
    """
    xs = np.tile(np.arange(depth_im.shape[1]), [depth_im.shape[0], 1])
    ys = np.tile(np.arange(depth_im.shape[0]), [depth_im.shape[1], 1]).T

    Xs = np.multiply(xs - K[0, 2], depth_im) * (1.0 / K[0, 0])
    Ys = np.multiply(ys - K[1, 2], depth_im) * (1.0 / K[1, 1])

    dist_im = np.linalg.norm(np.dstack((Xs, Ys, depth_im)), axis=2)
    return dist_im

def transform_pts_Rt(pts, R, t):
    """
    Applies a rigid transformation to 3D points.

    :param pts: nx3 ndarray with 3D points.
    :param R: 3x3 rotation matrix.
    :param t: 3x1 translation vector.
    :return: nx3 ndarray with transformed 3D points.
    """
    assert(pts.shape[1] == 3)
    pts_t = R.dot(pts.T) + t.reshape((3, 1))
    return pts_t.T

def project2img(model, img_size, K, R, t):

    model = transform_pts_Rt(model, R, t)

    img = np.zeros(img_size, dtype=np.float32)
    mask = np.zeros(img_size, dtype=np.bool)
    xpix = ((model[:, 0] * K[0, 0]) / model[:, 2]) + K[0, 2]
    ypix = ((model[:, 1] * K[1, 1]) / model[:, 2]) + K[1, 2]

    for i in range(0, xpix.shape[0]):
        x = int(xpix[i])
        y = int(ypix[i])

        if y > img_size[0]-1 or x > img_size[1]-1 or y < 0 or x < 0:
            print(x)
            print(y)
            continue

        if not mask[y, x]:
            img[y, x] = model[i,2] * 1000.0
            mask[y, x] = True
        elif (model[i, 2]*1000.0) < img[y, x]:
            img[y, x] = model[i, 2]*1000.0

    return img

def vsd(R_est, t_est, R_gt, t_gt, model, depth_test, K, delta, tau,
        cost_type='step'):
    """
    Visible Surface Discrepancy.
    :param R_est, t_est: Estimated pose (3x3 rot. matrix and 3x1 trans. vector).
    :param R_gt, t_gt: GT pose (3x3 rot. matrix and 3x1 trans. vector).
    :param model: Object model given by a dictionary where item 'pts'
    is nx3 ndarray with 3D model points.
    :param depth_test: Depth image of the test scene.
    :param K: Camera matrix.
    :param delta: Tolerance used for estimation of the visibility masks.
    :param tau: Misalignment tolerance.
    :param cost_type: Pixel-wise matching cost:
        'tlinear' - Used in the original definition of VSD in:
            Hodan et al., On Evaluation of 6D Object Pose Estimation, ECCVW 2016
        'step' - Used for SIXD Challenge 2017. It is easier to interpret.
    :return: Error of pose_est w.r.t. pose_gt.
    """

    im_size = (depth_test.shape[1], depth_test.shape[0])

    #depth_est = project2img(model, im_size, K, R_est, t_est)

    #depth_gt = project2img(model, im_size, K, R_gt, t_gt)

    depth_est = render(model, im_size, K, R_est, t_est, clip_near=100,
                                clip_far=10000, mode='depth')

    depth_gt = render(model, im_size, K, R_gt, t_gt, clip_near=100,
                               clip_far=10000, mode='depth')

    # Convert depth images to distance images
    dist_test = depth_im_to_dist_im(depth_test, K)
    dist_gt = depth_im_to_dist_im(depth_gt, K)
    dist_est = depth_im_to_dist_im(depth_est, K)

    # Visibility mask of the model in the ground truth pose
    visib_gt = estimate_visib_mask_gt(dist_test, dist_gt, delta)

    # Visibility mask of the model in the estimated pose
    visib_est = estimate_visib_mask_est(dist_test, dist_est, visib_gt, delta)

    #scaCro = 255.0 / np.nanmax(depth_est)
    #cross = np.multiply(depth_est, scaCro)
    #dep_sca = cross.astype(np.uint8)
    #cv2.imwrite("/home/sthalham/visTests/depth_est.jpg", dep_sca)

    # Intersection and union of the visibility masks
    visib_inter = np.logical_and(visib_gt, visib_est)
    visib_union = np.logical_or(visib_gt, visib_est)

    # Pixel-wise matching cost
    costs = np.abs(dist_gt[visib_inter] - dist_est[visib_inter])
    if cost_type == 'step':
        costs = costs >= tau
    elif cost_type == 'tlinear': # Truncated linear
        costs *= (1.0 / tau)
        costs[costs > 1.0] = 1.0
    else:
        print('Error: Unknown pixel matching cost.')
        exit(-1)

    # Visible Surface Discrepancy
    visib_union_count = visib_union.sum()
    visib_comp_count = visib_union_count - visib_inter.sum()
    if visib_union_count > 0:
        e = (costs.sum() + visib_comp_count) / float(visib_union_count)
    else:
        e = 1.0

    return e

def reproj(K, R_est, t_est, R_gt, t_gt, pts):
    """
    reprojection error.
    :param K intrinsic matrix
    :param R_est, t_est: Estimated pose (3x3 rot. matrix and 3x1 trans. vector).
    :param R_gt, t_gt: GT pose (3x3 rot. matrix and 3x1 trans. vector).
    :param model: Object model given by a dictionary where item 'pts'
    is nx3 ndarray with 3D model points.
    :return: Error of pose_est w.r.t. pose_gt.
    """
    pts_est = transform_pts_Rt(pts, R_est, t_est)
    pts_gt = transform_pts_Rt(pts, R_gt, t_gt)

    pixels_est = K.dot(pts_est.T)
    pixels_est = pixels_est.T
    pixels_gt = K.dot(pts_gt.T)
    pixels_gt = pixels_gt.T

    n = pts.shape[0]
    est = np.zeros((n, 2), dtype=np.float32)
    est[:, 0] = np.divide(pixels_est[:, 0], pixels_est[:, 2])
    est[:, 1] = np.divide(pixels_est[:, 1], pixels_est[:, 2])

    gt = np.zeros((n, 2), dtype=np.float32)
    gt[:, 0] = np.divide(pixels_gt[:, 0], pixels_gt[:, 2])
    gt[:, 1] = np.divide(pixels_gt[:, 1], pixels_gt[:, 2])

    e = np.linalg.norm(est - gt, axis=1).mean()
    return e

def add(R_est, t_est, R_gt, t_gt, pts):
    """
    Average Distance of Model Points for objects with no indistinguishable views
    - by Hinterstoisser et al. (ACCV 2012).

    :param R_est, t_est: Estimated pose (3x3 rot. matrix and 3x1 trans. vector).
    :param R_gt, t_gt: GT pose (3x3 rot. matrix and 3x1 trans. vector).
    :param model: Object model given by a dictionary where item 'pts'
    is nx3 ndarray with 3D model points.
    :return: Error of pose_est w.r.t. pose_gt.
    """
    pts_est = transform_pts_Rt(pts, R_est, t_est)
    pts_gt = transform_pts_Rt(pts, R_gt, t_gt)
    e = np.linalg.norm(pts_est - pts_gt, axis=1).mean()
    return e

def adi(R_est, t_est, R_gt, t_gt, pts):
    """
    Average Distance of Model Points for objects with indistinguishable views
    - by Hinterstoisser et al. (ACCV 2012).

    :param R_est, t_est: Estimated pose (3x3 rot. matrix and 3x1 trans. vector).
    :param R_gt, t_gt: GT pose (3x3 rot. matrix and 3x1 trans. vector).
    :param model: Object model given by a dictionary where item 'pts'
    is nx3 ndarray with 3D model points.
    :return: Error of pose_est w.r.t. pose_gt.
    """
    pts_est = transform_pts_Rt(pts, R_est, t_est)
    pts_gt = transform_pts_Rt(pts, R_gt, t_gt)

    # Calculate distances to the nearest neighbors from pts_gt to pts_est
    nn_index = spatial.cKDTree(pts_est)
    nn_dists, _ = nn_index.query(pts_gt, k=1)

    e = nn_dists.mean()
    return e

def re(R_est, R_gt):
    """
    Rotational Error.

    :param R_est: Rotational element of the estimated pose (3x1 vector).
    :param R_gt: Rotational element of the ground truth pose (3x1 vector).
    :return: Error of t_est w.r.t. t_gt.
    """
    assert(R_est.shape == R_gt.shape == (3, 3))
    error_cos = 0.5 * (np.trace(R_est.dot(np.linalg.inv(R_gt))) - 1.0)
    error_cos = min(1.0, max(-1.0, error_cos)) # Avoid invalid values due to numerical errors
    error = math.acos(error_cos)
    error = 180.0 * error / np.pi # [rad] -> [deg]
    return error

def te(t_est, t_gt):
    """
    Translational Error.

    :param t_est: Translation element of the estimated pose (3x1 vector).
    :param t_gt: Translation element of the ground truth pose (3x1 vector).
    :return: Error of t_est w.r.t. t_gt.
    """
    assert(t_est.size == t_gt.size == 3)
    error = np.linalg.norm(t_gt - t_est)
    return error


"""
@ART 基础数据数据结构
"""
from uuid import uuid1
from dataclasses import dataclass, field
from typing import *
from shapely.geometry import Point, LineString, Polygon

from treelib import Tree, Node

class GlobalTree:

    def __init__(self, tree=None, data_objects=None):
        self.tree = tree
        self.data_objects = data_objects

    # # 添加object
    # def add_object(self, one_object: DataObject, level):
    #     if self.tree.depth > 1:
    #         pass
    #
    # # 删除object
    # def delete_object(self, object_index: int):
    #     if tree.contains(object_index):
    #         tree.remove_node(object_index)
    #
    #
    # def insert_object(self, object_index: int, position):
    #
    #
    # def replace_object(self, one_object: DataObject, position):
    #
    #
    # def move_object_to_another_tree_position(self, position):

@dataclass(order=True, unsafe_hash=True)
class DataElement:
    """
    数据结构中最小的图形和语义信息储存类
    结构特征：用于存储每一个最基本的geometry对象（点/线/几何形状）；其中包含语义属性及几何属性；不存在任何嵌套与包含关系
    """
    # 几何属性
    geometry: Union[Point, LineString, Polygon] = field(default=None)
    shadow: Polygon = field(default=None)  # 几何物件对应的阴影, 仅包括geometry_realistic_state为True的Polygon

    # 语义属性
    id: str = field(default_factory=uuid1)     # 物件ID
    type: str = field(default="")             # 图层名
    group_list: tuple = field(default=None)  # 编组信息
    has_shadow: bool = field(default=False)    # 几何对象是否有阴影

@dataclass(order=True, unsafe_hash=True)
class DataObject:
    """
    物件类，逻辑结构
    结构特征：1.用于存储dxf文件中的一个Group单元；
            2.可以由ObjectElement组成，可以由DataObject组成，也可以两者共同组成
    """
    # 几何属性
    elements: List = field(default_factory=list)  # 所有dataElements

    # 语义属性
    id: str = field(default_factory=uuid1)  # 物件ID
    index: int = field(default=0)  # 組索引
    name: str = field(default=None)  # 编组名字
    global_tree: GlobalTree = field(default_factory=GlobalTree) # 全局树
    # tree: Tree = field(default_factory=Tree) # 关系树
    floor: int = field(default=0)  # 层数
    height: float = field(default=0.0)  # 高度
    annotations: str = field(default=None)  # 所有文字标注

    # 基准渲染层级
    zorder: int = field(default=0)

    @property
    def tree(self):
        if self.global_tree.tree.depth() > 1 and self.index in self.global_tree.tree.nodes:
            return self.global_tree.tree.subtree(self.index)
        else:
            return None

    # 所有DataElement
    def all_elements(self) -> List[DataElement]:
        elements = []
        object_indexes = self.tree.all_nodes()
        for index in object_indexes:
            elements.extend(self.global_tree.data_objects[index].elements)
        return elements

    # 所有DataObject
    def all_objects(self) -> List[DataElement]:
        objects = []
        object_indexes = self.tree.all_nodes()
        for index in object_indexes:
            objects.extend(self.global_tree.data_objects[index])
        return objects

    # 添加element
    def add_element(self, element: DataElement):
        if isinstance(element, DataElement) and element.geometry is not None:
            self.elements.append(element)
        else:
            raise Exception("物件中没有输入的元素ID")

    # 删除element
    def delete_element(self, element_id: str):
        if element_id in [item.id for item in self.elements]:
            index = max(self.elements, key=lambda x: x.id == element_id)
            self.elements.pop(index)
        else:
            raise Exception("物件中没有输入的元素ID")

def assemble_tree(data_elements:List[DataElement], data_objects:dict):
    """
    用于组装data_objects的关系树，传入是目前已有的element元素以及obj字典
    :param data_elements:
    :param data_objects:
    :return:
    """
    group_info = [each.group_list for each in data_elements]
    group_info = list(set(filter(lambda each: len(each)>0, group_info)))

    # 先构造一个全局的树，包含所有的树结构和层级
    global_tree = Tree() # 全局树
    global_tree.create_node("global_tree", "root")
    # 组装树
    for each in group_info:
        cur_order = list(each)
        cur_order.reverse()
        for i in range(len(cur_order)):
            all_node_tag = [node.tag for node in global_tree.all_nodes()]
            if i == 0 and cur_order[i] not in all_node_tag:
                global_tree.create_node(cur_order[i],cur_order[i],parent="root")
            elif i!=0 and cur_order[i] not in all_node_tag:
                global_tree.create_node(cur_order[i],cur_order[i],parent=cur_order[i-1])
    # 创建一个全局树，并把所有的对应的data object放进去
    cur_global_tree = GlobalTree(tree=global_tree, data_objects=data_objects)

    # 遍历全部data_objects对象，把全局树先放进去
    for each in data_objects.values():
        each.global_tree=cur_global_tree


#! /usr/bin/python3
import json
import os
import signal
import socket
import subprocess
import sys
import time

time_run = 2 * 24 * 60 * 60  # second
number_execute = 1
number_vm_count = 2

path_project = os.environ.get('PATH_PROJECT')
path_syzkaller = os.path.join(path_project, "03-syzkaller")
path_image = os.path.join(path_project, "workdir/image")
path_linux = os.path.join(path_project, "workdir/13-linux-clang-np")
path_kernel = os.path.join(path_linux, "arch/x86/boot/bzImage")
path_vmlinux_objdump = os.path.join(path_linux, "vmlinux.objdump")

name_driver = "built-in"
name_asm = name_driver + ".s"
name_bc = name_driver + ".bc"
name_dra_json = "dra.json"
name_syzkaller_json = "syzkaller.json"
file_log_syzkaller = "log_syzkaller.log"
file_log_dra = "log_dra.log"

path_current = os.getcwd()
path_dra = "dra"
path_syzkaller_manager = os.path.join(path_syzkaller, "bin/syz-manager")

name_workdir = "workdir"
file_image = "stretch.img"
file_ssh_key = "stretch.id_rsa"

def get_open_port():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(("", 0))
    s.listen(1)
    port = s.getsockname()[1]
    s.close()
    return port

class Process:
    def __init__(self):
        self.cmd_dra = ""
        self.cmd_syzkaller = ""
        self.drpc = "0"
        self.index = 0
        self.path = ""
        self.processes = []

    def execute(self, dra=False):
        path = os.path.join(path_current, str(self.index))
        while os.path.exists(path):
            self.index = self.index + 1
            path = os.path.join(path_current, str(self.index))
        self.path = path
        os.makedirs(self.path)
        print(self.path)

        cmd_cp_img = "cp -rf " + path_image + " " + os.path.join(self.path, "img")
        p_cp_img = subprocess.Popen(cmd_cp_img, shell=True, preexec_fn=os.setsid)
        p_cp_img.wait()

        f = open(os.path.join(path_current, name_syzkaller_json), "r")
        c = json.load(f)
        f.close()

        c["workdir"] = os.path.join(self.path, name_workdir)
        c["image"] = os.path.join(self.path, "img", file_image)
        c["sshkey"] = os.path.join(self.path, "img", file_ssh_key)
        c["syzkaller"] = path_syzkaller
        c["kernel_obj"] = path_linux
        c["vm"]["kernel"] = path_kernel
        c["vm"]["count"] = number_vm_count

        f = open(os.path.join(self.path, name_syzkaller_json), "w")
        json.dump(c, f, indent=4)
        f.close()

        os.chdir(self.path)
        self.execute_syzkaller(dependency_task=dra)
        self.execute_dra()

    def execute_syzkaller(self, dependency_task=False, dependency_priority=False):
        f = open(os.path.join(self.path, name_syzkaller_json), "r")
        c = json.load(f)
        f.close()
        c["http"] = "127.0.0.1:" + str(get_open_port())
        self.drpc = "127.0.0.1:" + str(get_open_port())
        c["drpc"] = self.drpc
        c["dependency_task"] = dependency_task
        c["dependency_priority"] = dependency_priority
        f = open(os.path.join(self.path, name_syzkaller_json), "w")
        json.dump(c, f, indent=4)
        f.close()

        self.cmd_syzkaller = path_syzkaller_manager + " -config=./" + name_syzkaller_json + " 2>" + file_log_syzkaller + " 1>&2 &"
        self.t0 = time.time()
        self.real_execute(self.cmd_syzkaller)

    def execute_dra(self):
        self.cmd_dra = path_dra + " -asm=../" + name_asm + " -objdump=" + path_vmlinux_objdump \
                       + " -bc=../" + name_bc + " -port=" + self.drpc \
                       + " ../" + name_dra_json + " 1>" + file_log_dra + " 2>&1 &"
        self.real_execute(self.cmd_dra)

    def real_execute(self, cmd):
        p = subprocess.Popen(cmd, shell=True)
        # p = subprocess.Popen(cmd, shell=True, start_new_session=True)
        self.processes.append(p)

    def close(self):
        for p in self.processes:
            os.killpg(os.getpgid(p.pid), signal.SIGTERM)

def main():
    dra = True
    if len(sys.argv) > 1:
        dra = False

    tasks = [Process() for i in range(number_execute)]
    for i in tasks:
        i.execute(dra)

    time.sleep(time_run)
    # time.sleep(30)

    for i in tasks:
        i.close()

if __name__ == "__main__":
    main()