from django.shortcuts import render
from django.shortcuts import redirect
from django.http.response import StreamingHttpResponse
from .eyeballTracking import FaceDetect
from .bloodFlow import BloodFlowDetect
# from.downloadframes(extra) import BloodFlowDetect
from .textureAnalysis import TextureDetect
from django.http import JsonResponse
from django.core.mail import send_mail
from django.http import HttpResponse
import os
import cv2
from django.core.cache import cache
from django.http import JsonResponse

# Create your views here.
def home(request):
    return render(request, "LivenessDetection/home.html", {'navbar' : 'home'})

def services(request):
    return render(request, "LivenessDetection/services.html", {'navbar' : 'services'})

def webcam(request):
    cache.set('result_available', False)
    cache.set('texture_result', None)
    cache.set('bloodflow_result', None)

    if request.method == 'POST':
        bloodflow_correct = request.POST.get('blood-flow', '')
        texture_correct = request.POST.get('texture', '')
        bloodflow_predicted = request.POST.get('bloodflow-actual', '') ### predicted
        texture_predicted = request.POST.get('texture-actual', '') ### predicted

        actual = int(bloodflow_predicted) if bloodflow_correct == 'yes' else (1 - int(bloodflow_predicted))

        fold_name = request.POST.get('fold-name', '')
        new_name = fold_name + '_' + str(actual)

        try:
            os.rename(fold_name, new_name)
        except FileNotFoundError:
            print(f"Folder not found.")
        except FileExistsError:
            print(f"A folder with the name already exists.")

        return render(request, "LivenessDetection/demo.html", {'navbar' : 'demo', 'type' : 'texture_feed'})

    return render(request, "LivenessDetection/demo.html", {'navbar' : 'demo', 'type' : 'texture_feed'})

def eyeball(request):
    return render(request, "LivenessDetection/demo.html", {'navbar' : 'demo', 'type' : 'video_feed'})

def bloodflow(request):
    cache.set('result_available', False)
    cache.set('texture_result', None)
    cache.set('bloodflow_result', None)
    return render(request, "LivenessDetection/demo.html", {'navbar' : 'demo', 'type' : 'bloodflow_feed'})

def usecase(request):
    return render(request, "LivenessDetection/usecase.html", {'navbar' : 'usecase'})

def aboutus(request):
    return render(request, "LivenessDetection/aboutus.html", {'navbar' : 'aboutus'})

def contact(request):
    if request.method == 'POST':
        name = request.POST.get('name', '')
        email = request.POST.get('email', '')
        subject = request.POST.get('subject', '')
        message = request.POST.get('message', '')

        if name and email and subject and message:
            # Send email
            send_mail(
                subject,
                message,
                email,
                ['your-email@example.com'],
                fail_silently=True,
            )
            return render(request, "LivenessDetection/contact.html", {'alert' : 'Thanks for contacting us!'})
        else:
            return render(request, "LivenessDetection/contact.html", {'alert' : 'Please fill all the required fields!'})
    else:
        return render(request, "LivenessDetection/contact.html")

counter = 0
def gen(camera):
    while True:
        global counter
        frame, loopEnd = camera.get_frame()
        if (loopEnd):
            counter += 1
            if (counter == 5):
                break

        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

def video_feed(request):
    return StreamingHttpResponse(gen(FaceDetect()),
					content_type='multipart/x-mixed-replace; boundary=frame')

def bf_gen(camera):
    while True:
        frame = camera.get_frame()

        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

def bloodflow_feed(request):
    return StreamingHttpResponse(bf_gen(BloodFlowDetect()),
					content_type='multipart/x-mixed-replace; boundary=frame')

def texture_gen(camera):
    cache.set('result_available', False)
    cache.set('texture_result', None)
    cache.set('bloodflow_result', None)
    counter = 0
    while True:
        frame = camera.get_frame()
        if camera.endloop:
            counter += 1
            if counter == 2:
                i = 0

                if not os.path.exists(camera.name):
                    os.mkdir(camera.name)

                for x in camera.all_frames:
                    # 0 is real
                    # 1 is fake
                    #filename of the form frame0_1 means texture algo predicted 1 for frame0
                    cv2.imwrite(f"{camera.name}/frame{i}_{x[1]}.png",x[0])
                    i += 1

                cache.set('result_available', True)
                cache.set('texture_result', camera.texture_result)
                cache.set('bloodflow_result', camera.bf_result)
                cache.set('fold_name', camera.name)
                break

        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

def texture_feed(request):
    folders = os.listdir('static/data')
    fold = 'static/data/video' + str(len(folders))

    return StreamingHttpResponse(texture_gen(TextureDetect(fold)),
					content_type='multipart/x-mixed-replace; boundary=frame')

def fetch_result(request):
    data = {'result_available': cache.get('result_available'), 'texture_result' : cache.get('texture_result'), 'bloodflow_result' : cache.get('bloodflow_result'), 'fold_name' : cache.get('fold_name')}
    return JsonResponse(data)


# This code looks at the data available at https://www.kaggle.com/snap/amazon-fine-food-reviews
# It cleans the data and treats the Summaries provided in the data as the golden data set
# for reference and accuracy measurements. We create 2 types of golden data:
#
# golden-with-removal.txt - Golden summary in lowercase after removal of stopwords
# golden-without-removal.txt - Golden summary in lowercase without removal of stopwords
#
# Similary the clean data is also written with and without stopwords removal as
# This is done to see the impact of stopwords on special character words in extractive summaries.

# author: appatil
import nltk
from nltk.corpus import *
import pandas as pd

# path of the raw data from kaggle
raw_reviews_path = '../../data/raw/Reviews-tst.csv'

# path for english language contractions
# you've -> you have
# he's -> he is
# Source: http://stackoverflow.com/questions/19790188/expanding-english-language-contractions-in-python
contractions_path = '../../data/clean/english-contractions.csv'

# Path for the golden summary
golden_with_removal_path = '../../data/golden/golden-with-removal-tst.txt'
golden_without_removal_path = '../../data/golden/golden-without-removal-tst.txt'

# Path for the cleansed reviews
clean_reviews_with_removal_path = '../../data/clean/clean-reviews-with-removal-tst.txt'
clean_reviews_without_removal_path = '../../data/clean/clean-reviews-without-removal-tst.txt'

# method to remove english language contractions
def remove_contractions(words, contractions):
    new_words = []
    for word in words:
        if word in contractions:
            new_words.append(contractions[word])
        else:
            new_words.append(word)

    return new_words

# removes the special characters from word
def remove_special_characters(word):
    word = re.sub(r'https?:\/\/.*[\r\n]*', '', word, flags=re.MULTILINE)
    word = re.sub(r'\<a href', '', word)
    word = re.sub(r'&', '', word)
    word = re.sub(r'[_"\-;%()|+&=*%.,!?:#$@\[\]/`~,]', '', word)
    word = re.sub(r'<br />', '', word)
    word = re.sub(r'\'', '', word)
    return word

# cleans a text
def clean_text(text, contractions, stopwords):

    # Convert words to lower case
    text = text.lower()
    sentences = nltk.sent_tokenize(text)
    new_sentences_without_removal = []
    new_sentences_with_removal = []

    for sentence in sentences:
        words = nltk.word_tokenize(sentence)

        # Replace contractions with longer forms
        words = remove_contractions(words, contractions)

        # Remove special characters
        words_without_removal = [remove_special_characters(word) for word in words]
        words_with_removal = remove_stopwords(words_without_removal, stopwords)

        new_sentences_without_removal.append(" ".join([word for word in words_without_removal if word.isalpha()]) + ".")
        new_sentences_with_removal.append(" ".join([word for word in words_with_removal if word.isalpha()]) + ".")

    return (" ".join([s for s in new_sentences_without_removal if s != "."]), " ".join([s for s in new_sentences_with_removal if s != "."]))

# removes stopwords from sentence
def remove_stopwords(words, stopwords):
    return [word for word in words if word not in stopwords]

# read the raw reviews
raw_reviews = pd.read_csv(raw_reviews_path)

# Remove null values and unneeded features
raw_reviews = raw_reviews.dropna()
raw_reviews = raw_reviews.drop(['Id','ProductId','UserId','ProfileName','HelpfulnessNumerator','HelpfulnessDenominator',
                        'Score','Time'], 1)
raw_reviews = raw_reviews.reset_index(drop=True)

# read the contractions
contractions_data = pd.read_csv(contractions_path)
contractions = dict(zip(list(contractions_data.contraction), list(contractions_data.phrase)))

# NLTK stopwords
stopwords = nltk.corpus.stopwords.words('english')
golden_with_removal = open(golden_with_removal_path, 'w')
golden_without_removal = open(golden_without_removal_path, 'w')
clean_reviews_with_removal = open(clean_reviews_with_removal_path, 'w')
clean_reviews_without_removal = open(clean_reviews_without_removal_path, 'w')

# this is just for printing progress
progress_count = []
for i in range(0, 100, 7):
    progress_count.append(int(i/100 * len(raw_reviews)))

print("Cleaning Summaries ... ", end="", flush=True)
for i, summary in enumerate(raw_reviews.Summary):
    (summary_without_removal, summary_with_removal) = clean_text(summary, contractions, stopwords)
    golden_without_removal.write("{}\n".format(summary_without_removal))
    golden_with_removal.write("{}\n".format(summary_with_removal))

    # Prints the progress count
    if i in progress_count:
        print ("{}%..".format(int(i/len(raw_reviews)*100)), end="", flush=True)
print("100%")

print("Cleaning Reviews ... ", end="", flush=True)
for i, text in enumerate(raw_reviews.Text):

    (text_without_removal, text_with_removal) = clean_text(text, contractions, stopwords)
    clean_reviews_without_removal.write("{}\n".format(text_without_removal))
    clean_reviews_with_removal.write("{}\n".format(text_with_removal))

    # Prints the progress count
    if i in progress_count:
        print ("{}%..".format(int(i/len(raw_reviews)*100)), end="", flush=True)
print("100%")


import numpy as np
import cv2
from matplotlib import pyplot as plt

def mask(bgr_img,hsv_img,low,up):
    lower_color = np.array(low)
    upper_color = np.array(up)
    mask_color = cv2.inRange(hsv_img,lower_color,upper_color)
    return cv2.bitwise_and(bgr_img,bgr_img,mask=mask_color)

def get_center_lines(Z):
    for i in range(0,len(Z)):
        if Z[i][1]<0.5:
            Z[i][1]+= np.pi

    Z = np.float32(Z)
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    compactness,labels,centers = cv2.kmeans(Z[:,1],3,criteria,10,cv2.KMEANS_RANDOM_CENTERS)

    A = Z[labels.ravel()==0]
    B = Z[labels.ravel()==1]
    C = Z[labels.ravel()==2]

    ret1,label1,centers1=cv2.kmeans(A,min(7,len(A)),criteria,10,cv2.KMEANS_RANDOM_CENTERS)
    ret2,label2,centers2=cv2.kmeans(B,min(7,len(B)),criteria,10,cv2.KMEANS_RANDOM_CENTERS)
    ret3,label3,centers3=cv2.kmeans(C,min(7,len(C)),criteria,10,cv2.KMEANS_RANDOM_CENTERS)

    return (centers1, centers2, centers3)

def polar2cartesian(rho,theta):
    if theta > np.pi:
        theta -= np.pi

    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a*rho
    y0 = b*rho
    x1 = int(x0 +1000*(-b))
    y1 = int(y0 +1000*(a))
    x2 = int(x0 -1000*(-b))
    y2 = int(y0 -1000*(a))

    return (x1,y1),(x2,y2)

img0 = cv2.imread('2.jpg')
while(1):
    k=cv2.waitKey(1)&0xFF
    if k==27:
        break

    img1=img0.copy()
    img2=img0.copy()
    img3=img0.copy()
    img4=img0.copy()
    hsv=cv2.cvtColor(img0,cv2.COLOR_BGR2HSV)
    res = mask(img0,hsv,[0,100,0],[179,255,255])
    dst=cv2.GaussianBlur(res,(13,13),0)
    edges = cv2.Canny(dst,100,120)
    lines = cv2.HoughLines(edges,1,np.pi/30,45)

    if lines is not None:
        for rho, theta in lines[0]:
            (x1,y1),(x2,y2) = polar2cartesian(rho,theta)
            cv2.line(img1,(x1,y1),(x2,y2),(0,0,255),2)

        center1, center2, center3 = get_center_lines(lines[0])

        for rho, theta in center1:
            (x1,y1),(x2,y2) = polar2cartesian(rho,theta)
            cv2.line(img2,(x1,y1),(x2,y2),(0,0,255),2)

        for rho, theta in center2:
            (x1,y1),(x2,y2) = polar2cartesian(rho,theta)
            cv2.line(img3,(x1,y1),(x2,y2),(0,0,255),2)

        for rho, theta in center3:
            (x1,y1),(x2,y2) = polar2cartesian(rho,theta)
            cv2.line(img4,(x1,y1),(x2,y2),(0,0,255),2)

        cv2.imshow("img",img1)
        cv2.imshow("v1",img2)
        cv2.imshow("v2",img3)
        cv2.imshow("v3",img4)
        break

cv2.waitKey(0)
cv2.destroyAllWindows()


__author__ = 'SharonYU'

import pandas as pd
import pymongo
import datetime
import copy
pd.set_option('display.max_rows', 500)
pd.set_option('display.max_columns', 50)

def new_daily_eod(data_cursor: pymongo.cursor, target_time: int) -> pd.DataFrame:
    '''
    This function aims to speed up the time cost of former split method which split the data day by day
    The main difference is that the function directly read data from mongodb and split the data for all days in one call
    params:
    data_cursor: pymongo.cursor contain all collection for a single index from begin date to end
    target_time: int64, the target time we want to regenerate EOD
    '''

    # to identify the period inside a date, we denote A as the first half day, and B as the rest
    # which means in the afternoon is A, in the morning is B

    # init values and record the first day
    result_record = []
    value_ = data_cursor.next()
    first_day = value_['nActionDay']
    crt_day = first_day

    # record the current day
    while True:

        while value_['iVolume'] == 0:
            value_ = data_cursor.next()

        # update morning record
        morning_record = copy.deepcopy(value_)
        try:
            value_ = data_cursor.next()
        except:
            break

        # for the rest records in the morning
        while value_['nTime'] < target_time:
            if value_['iVolume'] == 0:
                pass
            else:
                # update the nMatch price
                morning_record['nLastIndex'] = value_['nLastIndex']

                # update the high low price
                morning_record['nHighIndex'] = max(morning_record['nHighIndex'], value_['nHighIndex'])
                morning_record['nLowIndex'] = min(morning_record['nLowIndex'], value_['nLowIndex'])

                # update volume and amount
                morning_record['iVolume'] += value_['iVolume']
                morning_record['iTurnover'] += value_['iTurnover']

            # call the next iteration
            try:
                value_ = data_cursor.next()
            except:
                # print('no record left')
                break

        # rename the morning dataframe
        for item in [key for key in morning_record.keys() if key != 'szWindCode']:
            morning_record[item + '_B'] = morning_record.pop(item)

        # get afternoon dataframe
        # for the first in the afternoon
        while (value_['iVolume'] == 0) & (value_['nTime'] < 1500e5):
            value_ = data_cursor.next()

        afternoon_record = copy.deepcopy(value_)
        value_ = data_cursor.next()
        # for the rest in the afternoon
        while value_['nActionDay'] == crt_day:

            if value_['iVolume'] == 0:
                # if no trade happens in this minute
                pass
            else:
                # update the nMatch price
                afternoon_record['nLastIndex'] = value_['nLastIndex']

                # update the high low price
                afternoon_record['nHighIndex'] = max(afternoon_record['nHighIndex'], value_['nHighIndex'])
                afternoon_record['nLowIndex'] = min(afternoon_record['nLowIndex'], value_['nLowIndex'])

                # update volume and amount
                afternoon_record['iVolume'] += value_['iVolume']
                afternoon_record['iTurnover'] += value_['iTurnover']

            # call iterate
            try:
                value_ = data_cursor.next()
            except:
                break

        # rename afternoon dataframe
        for item in [key for key in afternoon_record.keys() if key != 'szWindCode']:
            afternoon_record[item + '_A'] = afternoon_record.pop(item)

        # append the records
        # if this is the first day, we only keep the afternoon record for second day's use
        # else we keep both the morning and afternoon record and record as B and A date results
        if crt_day == first_day:
            yesterday_df = afternoon_record
            del morning_record
        else:
            del morning_record['szWindCode']
            result_record.append({**yesterday_df, **morning_record})
            del morning_record
            yesterday_df = copy.deepcopy(afternoon_record)

        # update current day
        crt_day = value_['nActionDay']

    result = pd.DataFrame(result_record)

    # adjust data types
    result[result.columns.drop(['szWindCode', 'nActionDay_A', 'nActionDay_B'])] = \
        result[result.columns.drop(['szWindCode', 'nActionDay_A', 'nActionDay_B'])].astype('int64')

    result[['szWindCode', 'nActionDay_A', 'nActionDay_B']] = \
        result[['szWindCode', 'nActionDay_A', 'nActionDay_B']].astype(str)

    result = result[result.columns.drop(['nTime_A', 'nTime_B'])]

    # rename some columns to differ from those stock columns
    result.rename(columns={'iVolume_A': 'iVolumeIndex_A',
                           'iVolume_B': 'iVolumeIndex_B',
                           'iTurnover_A': 'iTurnoverIndex_A',
                           'iTurnover_B': 'iTurnoverIndex_B'},
                           inplace=True)

    return result

if __name__ == '__main__':
    begin_time = datetime.datetime.now()
    # get data
    target_time = 140000000
    stock_id = '000300.SH'
    begin_date = '20190601'
    end_date = '20200630'

    from regenerate_EOD.utils.read_minite_bar import ReadMinBarMongoDB
    data = ReadMinBarMongoDB(begin_date=begin_date, end_date=end_date, id=stock_id, type='snap_index')
    cursor = data.read_all_days()
    df = new_daily_eod(cursor, target_time)

    print(df.info())
    test_array = df.to_records(index=False)
    shape, dtype = test_array.shape, test_array.dtype
    print(shape, dtype)
    end_time = datetime.datetime.now()
    print(end_time - begin_time)
    # print(df)


import sys

#from PySide6.QtWidgets import QApplication, QWidget, QPushButton, QMessageBox, QFileDialog, QMainWindow, QLabel, QMenuBar, QMenu, QTabWidget, QFormLayout, QLineEdit, QHBoxLayout, QRadioButton, QCheckBox, QGridLayout, QSpinBox, QToolButton, QLCDNumber, QFrame, QVBoxLayout, QScrollBar
#from PySide6.QtGui import QCloseEvent, QAction, QKeySequence

#from PySide6.QtCore import Qt

#from PySide6.QtGui import QAction, QIcon, QKeySequence, QScreen, QPalette

#from PySide6.QtCore import QPointF
#from PySide6.QtGui import QPainter
#from PySide6.QtWidgets import QMainWindow, QApplication
#from PySide6.QtCharts import QChart, QChartView, QLineSeries,QScatterSeries,QValueAxis

#from PySide6.QtCore import Slot

from PySide6.QtWidgets import *
from PySide6.QtGui import *
from PySide6.QtCore import *
from PySide6.QtCharts import *

from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qtagg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt

#from qtrangeslider import QRangeSlider

#import gui.toto as toto
#import gui.tab as tab

from ..core import *

from pathlib import Path

import numpy as np

class PowerBar(QWidget):
    def __init__(self,parent=None):
        super(PowerBar, self).__init__(parent)

        layout = QHBoxLayout()

        #self.enable = QCheckBox("Enable")
        #layout.addWidget(self.enable)

        self.firstButton = QToolButton()
        #icon = QIcon.fromTheme("go-first-symbolic.svg")
        icon = QIcon.fromTheme("go-first", QIcon("xlight/icon/go-first.png"))
        self.firstButton.setIcon(icon)
        layout.addWidget(self.firstButton)

        self.previousButton = QToolButton()
        #icon = QIcon.fromTheme("go-previous-symbolic.svg")
        icon = QIcon.fromTheme("go-previous", QIcon("xlight/icon/go-previous.png"))
        self.previousButton.setIcon(icon)
        layout.addWidget(self.previousButton)

        self.lcd = QLCDNumber()
        #self.lcd.resize(40, 40)
        layout.addWidget(self.lcd)

        self.nextButton = QToolButton()
        #icon = QIcon.fromTheme("go-next-symbolic.svg")
        icon = QIcon.fromTheme("go-next", QIcon("xlight/icon/go-next.png"))
        self.nextButton.setIcon(icon)
        layout.addWidget(self.nextButton)

        self.lastButton = QToolButton()
        #icon = QIcon.fromTheme("go-last-symbolic.svg")
        icon = QIcon.fromTheme("go-last", QIcon("xlight/icon/go-last.png"))
        self.lastButton.setIcon(icon)
        layout.addWidget(self.lastButton)

        self.setLayout(layout)

class InfoWidget(QWidget):
    def __init__(self,parent=None):
        super(InfoWidget, self).__init__(parent)

        self.profil=None

        layout = QVBoxLayout()
        self.KhiLabel=QLabel()
        self.PhiLabel=QLabel()
        self.GammaLabel=QLabel()
        self.TimeLabel=QLabel()
        self.AnodeLabel=QLabel()
        self.R2Label=QLabel()
        layout.addWidget(self.KhiLabel)
        layout.addWidget(self.PhiLabel)
        layout.addWidget(self.GammaLabel)
        layout.addWidget(self.TimeLabel)
        layout.addWidget(self.AnodeLabel)
        layout.addWidget(self.R2Label)

        #self.enable = QCheckBox("Enable")
        self.enable = QPushButton()
        self.enable.setCheckable(True)
        layout.addWidget(self.enable)

        #redb = QPushButton('Red', self)
        #redb.setCheckable(True)
        #layout.addWidget(redb)
        #self.enable.stateChanged.connect(lambda:self.stateProfil())
        self.Set()

        self.setLayout(layout)

    def Set(self,profil=None):
        if profil:
            khi="%1.2f" % (profil.Khi)
            self.KhiLabel.setText("\u03c7="+khi+"\u00B0")
            phi="%1.2f" % (profil.Phi)
            self.PhiLabel.setText("\u03c6="+phi+"\u00B0")
            gamma="%1.2f" % (profil.Gamma)
            self.GammaLabel.setText("\u03b3="+gamma+"\u00B0")
            time="%1.2f" % (profil.Time)
            self.TimeLabel.setText("Time="+time+"s")
            self.AnodeLabel.setText("Anode="+str(profil.Anode.name))

            self.KhiLabel.setVisible(True)
            self.PhiLabel.setVisible(True)
            self.GammaLabel.setVisible(True)
            self.TimeLabel.setVisible(True)
            self.AnodeLabel.setVisible(True)
            #self.R2Label.setVisible(True)
            self.enable.setVisible(True)

            if profil.Fun.IsInit:
                R2="%1.3f" % (profil.Fun.r_squared)
                self.R2Label.setText("R\u00b2="+R2)
                self.R2Label.setVisible(True)
            else:
                self.R2Label.setText("R\u00b2=")
                self.R2Label.setVisible(False)
            self.profil=profil
            if profil.IsEnable:
                self.enable.setChecked(True)
            else:
                self.enable.setChecked(False)

            #self.enable.stateChanged.connect(self.stateProfil())
        else:
            self.KhiLabel.setText("\u03c7=")
            self.PhiLabel.setText("\u03c6=")
            self.GammaLabel.setText("\u03b3=")
            self.TimeLabel.setText("Time=")
            self.AnodeLabel.setText("Anode=")
            self.R2Label.setText("R\u00b2=")
            self.KhiLabel.setVisible(False)
            self.PhiLabel.setVisible(False)
            self.GammaLabel.setVisible(False)
            self.TimeLabel.setVisible(False)
            self.AnodeLabel.setVisible(False)
            self.R2Label.setVisible(False)
            self.enable.setChecked(False)
            self.enable.setVisible(False)

        if self.enable.isChecked():
            self.enable.setText("Enable")
            self.enable.setStyleSheet('QPushButton {background-color: green}')
        else:
            self.enable.setText("Disable")
            self.enable.setStyleSheet('QPushButton {background-color: red}')
            #self.profil=None
    #def stateProfil(self):
    #    print("HHH")
    #    if self.profil:
    #        self.profil.SetEnable(self.enable.isChecked())
    #        if self.enable.isChecked():
    #            #self.profil.Enable=True
    #            print("toto")
    #        else:
    #            #self.profil.IsEnable=False
    #            print("tutu")

#from QCharts import *

def format_coord(x, y):
    xlabel=u"2\u03b8="
    ylabel="Intensity="
    xvalue="%1.2f" % (x)
    yvalue="%1.2f" % (y)
    xunity=u"\u00B0"
    yunity=" cps"
    return xlabel+xvalue+xunity+", "+ylabel+yvalue+yunity
    #return '2u\03b8=%1.4f, Intensity=%1.4f' % (x, y)

class InspectWidget(QWidget):
    def __init__(self,parent=None, model=None):
        super(InspectWidget, self).__init__(parent)
        self.model=model

        self.figure = plt.figure()
        self.ax=self.figure.add_subplot(111)

        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)
        #self.toolbar.removeAction('forward')
        unwanted_buttons=['Back','Forward','Subplots','Customize']
        for x in self.toolbar.actions():
            #print(x.text())
            if x.text() in unwanted_buttons:
                self.toolbar.removeAction(x)

        #self.toolbar.toolitems=[('Home', 'Reset original view', 'home', 'home')]
        #self.toolbar = NavigationToolbar(self.canvas)
        self.layout = QGridLayout(self)

        self.Displacement=PowerBar(self)
        self.layout.addWidget(self.Displacement,0,0,1,1)
        self.iprofil=0

        #self.layout.addWidget(self.ChartView,1,0,1,1)
        self.layout.addWidget(self.toolbar,0,1,1,1)
        self.layout.addWidget(self.canvas,1,0,1,2)

        self.info=InfoWidget()
        self.layout.addWidget(self.info,1,2)
        self.info.enable.clicked.connect(lambda:self.ChangeState())
        self.ChangeState()

        self.Displacement.nextButton.clicked.connect(self.Next)
        self.Displacement.lastButton.clicked.connect(self.Last)

        self.Displacement.previousButton.clicked.connect(self.Previous)
        self.Displacement.firstButton.clicked.connect(self.First)

        self.setLayout(self.layout)
        self.SetDisplay()

        return

    def ChangeState(self):
        #print("zzz")
        if self.iprofil>=0 and self.iprofil<len(self.model.profils):
            self.model.profils[self.iprofil].SetEnable(self.info.enable.isChecked())
            self.ReLoad()

    def Next(self):
        self.iprofil+=1
        self.iprofil=min(self.iprofil,len(self.model.profils)-1)
        self.iprofil=max(0,self.iprofil)
        #self.Displacement.lcd.display(self.iprofil+1)
        #self.ReLoad()
        self.SetDisplay()
    def Last(self):
        self.iprofil=len(self.model.profils)-1
        self.iprofil=max(0,self.iprofil)
        #self.Displacement.lcd.display(self.iprofil+1)
        #self.ReLoad()
        self.SetDisplay()

    def Previous(self):
        self.iprofil-=1
        self.iprofil=max(0,self.iprofil)
        #self.Displacement.lcd.display(self.iprofil+1)
        #self.ReLoad()
        self.SetDisplay()
    def First(self):
        self.iprofil=0
        #self.Displacement.lcd.display(self.iprofil+1)
        self.SetDisplay()
        #self.ReLoad()
    def SetDisplay(self):
        self.Displacement.lcd.display(self.iprofil+1)
        self.ReLoad()

    def ReLoad(self):
        self.ax.clear()
        self.ax.set_xlabel(u"2\u03b8 (deg)", fontsize=20)
        self.ax.set_ylabel('Intensity (cps)', fontsize=20)
        self.ax.format_coord = format_coord
        self.figure.tight_layout()

        if self.iprofil>=0 and self.iprofil<len(self.model.profils):
            ppp=self.model.profils[self.iprofil]
            self.info.Set(self.model.profils[self.iprofil])
            self.ax.plot(ppp.TwoTheta,ppp.Intensity,'*-',label="experiment", color='black')
            if ppp.Fun.IsInit and ppp.IsEnable:
                ii=ppp.GetFunctionData(False)
                self.ax.plot(ppp.TwoTheta,ii, '-',label="model", color="red")
        else:
            self.info.Set()

        self.canvas.draw()


#!/usr/bin/env python
import sys
import argparse

def parse_args():
    ''' Parses command line argument. '''
    help_text = 'converts markdown to html'
    parser = argparse.ArgumentParser(description=help_text)
    parser.add_argument('filename',
                        action='store',
                        default='-',
                        type=str,
                        nargs='?',
                        help='Input markdown filename. \'-\' for stdin.')
    return parser.parse_args()

SYM_TITLE = '#'
SYM_SUBTITLE = '##'
SYM_TRIPLE_TICK = '```'
SYM_BEGIN_LINK_IMAGE = '!'
SYM_BEGIN_LINK = '['
SYM_END_LINK = ']'
SYM_BEGIN_REF = '('
SYM_END_REF = ')'

TICK_STATE_BEGIN = 1
TICK_STATE_END = 2

TEMPLATE_LINK = '{text}'
TEMPLATE_IMAGE = ''
TEMPLATE_TITLE = '
{text}
'
TEMPLATE_SUBTITLE = '
{text}
'
TEMPLATE_TICK_BEGIN = '
'
TEMPLATE_TICK_END = '
'
TEMPLATE_LINE = '
{text}
'

class LinkParser:

    def __init__(self, line, begin_link, end_link, begin_ref, end_ref, is_image):
        self.line = line
        self.begin_link = begin_link
        self.end_link = end_link
        self.begin_ref = begin_ref
        self.end_ref = end_ref
        self.is_image = is_image

    @classmethod
    def find(cls, line):
        state = SYM_BEGIN_LINK
        begin_link = None
        end_link = None
        begin_ref = None
        end_ref = None
        is_image = False
        for i, c in enumerate(line):
            if state == SYM_BEGIN_LINK and c == SYM_BEGIN_LINK:
                begin_link = i
                state = SYM_END_LINK
            elif state == SYM_END_LINK and c == SYM_END_LINK:
                end_link = i
                state = SYM_BEGIN_REF
            elif state == SYM_BEGIN_REF and c == SYM_BEGIN_REF:
                begin_ref = i
                state = SYM_END_REF
            elif state == SYM_END_REF and c == SYM_END_REF:
                end_ref = i
                # detect if there is an '!' right before the '[', then we'll parse this as an "image" tag
                if line[begin_link-1] == '!':
                    is_image = True
                return cls(line, begin_link, end_link, begin_ref, end_ref, is_image)
        return None

    @property
    def result(self):
        text = self.line[self.begin_link+1:self.end_link]
        ref = self.line[self.begin_ref+1:self.end_ref]
        tag = (TEMPLATE_IMAGE.format(ref=ref, text=text)
                if self.is_image else
                TEMPLATE_LINK.format(ref=ref, text=text))
        # cut out the '!' before the image tag if it exists.
        offset_if_image = (1 if self.is_image else 0)
        ret = [
            self.line[:self.begin_link - offset_if_image],
            tag,
            self.line[self.end_ref+1:],
        ]
        ret = ''.join(ret)
        return ret

    @classmethod
    def replace(cls, line):
        while cls.find(line):
            line = cls.find(line).result
        return line

def process_line(line, tick_state):

    if line.startswith(SYM_TRIPLE_TICK):

        if tick_state == TICK_STATE_BEGIN:
            _, text = line.split(SYM_TRIPLE_TICK, 1)
            line = TEMPLATE_TICK_BEGIN + text.strip() + '\n'
            tick_state = TICK_STATE_END

        elif tick_state == TICK_STATE_END:
            _, text = line.split(SYM_TRIPLE_TICK, 1)
            line = TEMPLATE_TICK_END + text.strip() + '\n'
            tick_state = TICK_STATE_BEGIN

    elif tick_state == TICK_STATE_END:

        pass  # don't format anything inside the ticks

    elif line.startswith(SYM_SUBTITLE):
        _, text = line.split(SYM_SUBTITLE, 1)
        line = TEMPLATE_SUBTITLE.format(text=text.strip()) + '\n'

    elif line.startswith(SYM_TITLE):
        _, text = line.split(SYM_TITLE, 1)
        line = TEMPLATE_TITLE.format(text=text.strip()) + '\n'

    else:
        if len(line.strip()) == 0:
            pass  # ignore a pure-whitespace line
        else:
            line = TEMPLATE_LINE.format(text=line.strip()) + '\n'

    # only replace links if we're not inside the ticks
    if tick_state == TICK_STATE_BEGIN:
        line = LinkParser.replace(line)

    return line, tick_state

def process_file(file):
    tick_state = TICK_STATE_BEGIN
    for line in file:
        line, tick_state = process_line(line, tick_state)
        yield line

def main():
    args = parse_args()
    file = open(args.filename, 'r') if args.filename != '-' else sys.stdin
    for line in process_file(file):
        sys.stdout.write(line)

def test_replace_links():
    test_input = "Hello [google]  (http://www.google.com/)"
    expected = 'Hello google'
    result = LinkParser.replace(test_input)
    assert result == expected, "'%s' != '%s'" % (result, expected)

def test():
    test_replace_links()

if __name__ == '__main__':
    main()


import pandas as pd
import numpy as np
from scipy.interpolate import CubicSpline

def heaviside_step(x):
    return np.heaviside([x], 1)[0]

def normal_trapezoidal(m, suitable_min, suitable_max, optimal_min, optimal_max):
    """
    m: value in t
    """
    if np.isnan(m):
        ret = 0.25
    elif (m < suitable_min) or (m > suitable_max):
        ret = 0
    else:
        ret = min(
            (
                (m - suitable_min) / (optimal_min - suitable_min),
                1,
                (suitable_max - m) / (suitable_max - optimal_max),
            )
        )

    return ret

def left_trapezoidal(m, suitable_min, suitable_max, optimal_max):
    """
    m: value in t
    """
    if np.isnan(m):
        ret = 0.25
    elif (m < suitable_min) or (m > suitable_max):
        ret = 0
    else:
        ret = min((1, (suitable_max - m) / (suitable_max - optimal_max)))

    return ret

def source_data(**kwargs):
    if kwargs["path"]:
        df = pd.read_csv(kwargs["path"], sep=";") #Temp;DO;NH4;NO2;ABW;DOC
        doc = df["DOC"].tolist()
        score_uia = []
        score_o2 = []
        score_temp = []

        for i in doc:
            score_uia.append(
                left_trapezoidal(
                    df[df["DOC"] == i]["NH4"].values[0],
                    kwargs["ua_suitable_min"],
                    kwargs["ua_suitable_max"],
                    kwargs["ua_optimal_max"],
                )
            )

            score_o2.append(
                normal_trapezoidal(
                    df[df["DOC"] == i]["DO"].values[0],
                    kwargs["do_suitable_min"],
                    kwargs["do_suitable_max"],
                    kwargs["do_optimal_min"],
                    kwargs["do_optimal_max"],
                )
            )

            score_temp.append(
                normal_trapezoidal(
                    df[df["DOC"] == i]["Temp"].values[0],
                    kwargs["temp_suitable_min"],
                    kwargs["temp_suitable_max"],
                    kwargs["temp_optimal_min"],
                    kwargs["temp_optimal_max"],
                )
            )

            suhu = df[["DOC", "Temp"]]

    else:
        try:
            chem = pd.read_csv(kwargs["chemical_path"])
            bio = pd.read_csv(kwargs["biological_path"])

            bio.replace("-", np.nan, inplace=True)
            bio.fillna(np.nan, inplace=True)

            chem.replace("-", np.nan, inplace=True)
            chem.fillna(np.nan, inplace=True)
        except:
            chem = pd.read_csv("data/data_chemical_v2.csv")
            bio = pd.read_csv("data/data_sample - biological.csv")

        doc = chem["Doc"].tolist()

        score_uia = []
        score_o2 = []
        score_temp = []

        for i in doc:
            score_uia.append(
                left_trapezoidal(
                    chem[chem["Doc"] == i]["uia"].values[0],
                    kwargs["ua_suitable_min"],
                    kwargs["ua_suitable_max"],
                    kwargs["ua_optimal_max"],
                )
            )

            score_o2.append(
                normal_trapezoidal(
                    bio[bio["DOC"] == i]["DO_s"].values[0],
                    kwargs["do_suitable_min"],
                    kwargs["do_suitable_max"],
                    kwargs["do_optimal_min"],
                    kwargs["do_optimal_max"],
                )
            )

            score_temp.append(
                normal_trapezoidal(
                    bio[bio["DOC"] == i]["Suhu_s"].values[0],
                    kwargs["temp_suitable_min"],
                    kwargs["temp_suitable_max"],
                    kwargs["temp_optimal_min"],
                    kwargs["temp_optimal_max"],
                )
            )

            suhu = bio[["DOC", "Suhu_s"]]

    f_uia = CubicSpline(doc, score_uia)
    f_o2 = CubicSpline(doc, score_o2)
    f_temp = CubicSpline(doc, score_temp)

    return f_uia, f_o2, f_temp, suhu

def score_csc_compute(
    biomass, volume, csc_suitable_min=0.00, csc_suitable_max=5, csc_optimal_max=3
):

    return left_trapezoidal(
        biomass / volume, csc_suitable_min, csc_suitable_max, csc_optimal_max
    )

def price_function(path, sep=";", col_size="size_count", col_price="price"):
    """
    path: path file for the price's data
    sep: delimiter/separator for the csv file
    col_size: columns name for size count of shrimp
    col_price: columns name for price of shrimp
    """
    df = pd.read_csv(path, sep=sep)
    x_sample = df[col_size].tolist()[::-1]
    y_sample = df[col_price].tolist()[::-1]
    f = CubicSpline(x_sample, y_sample, bc_type="natural")
    return f

def feed_formula3(path, sep=";", colname="Formula 3"):
    df = pd.read_csv(path, sep=sep)
    return df[colname].tolist()

def get_cycle_data(index, t, df):
    # index and t must be at the same row
    if t < index:
        start_index = index - t + 1
    else:
        start_index = index - index

    data = df.loc[start_index:index]
    if data.shape[0] == 1:
        data = df.loc[start_index:index+1]

    return data

def generate_interpolate_function(df, col_doc, col_function):
    f = CubicSpline(df[col_doc].values, df[col_function].values)
    return f

def generate_spline_function(df, col_doc, condition, col_function="Temp", biochem_type="temperature"):
    # col_function example is temperature
    # condition (suitable_min, optimal_min, optimal_max, suitable_max)
    if biochem_type == "temperature":
        data = [normal_trapezoidal(x, condition[0], condition[3], condition[1], condition[2]) for x in df[col_function].values]
    elif biochem_type == "nh4":
        data = [left_trapezoidal(x, condition[0], condition[3], condition[2]) for x in df[col_function].values]
    else:
        data = [normal_trapezoidal(x, condition[0], condition[3], condition[1], condition[2]) for x in df[col_function].values]

    f = CubicSpline(df[col_doc].values, data)
    return f

def integrate_function(t, function, condition, kind):
    """
    t: the time value
    function: interpolation function
    condition: list of condition
    type: type of function. ex: temperature
    """
    if (kind == "temperature") or (kind == "do"):
        return normal_trapezoidal(function(t), condition[0], condition[3], condition[1], condition[2])
    elif kind == "nh4":
        return left_trapezoidal(function(t), condition[0], condition[3], condition[2])

def get_cycle_range(df, col_doc="DOC"):
    list_index = df[df[col_doc] == 1].index
    cycles = []
    for index, value in enumerate(list_index):
        if value != list_index[-1]:
            cycles.append([value, list_index[index+1]])
        else:
            cycles.append([value])

    return cycles

import requests
from bs4 import BeautifulSoup

def fahrenheit_to_celcius(temperature):
    return 5/9*(temperature - 32)

def get_temperature_data():
    file = requests.get("https://weather.com/weather/tenday/l/6f82c91e634d2dcbac7505574acad8ec83e506bcf6ab5aa7664be72ffc76555e")
    soup = BeautifulSoup(file.content, "html.parser")

    ten_html_data = soup.find("div", {"class":"DailyForecast--DisclosureList--msYIJ"}).find_all("div", {"data-testid": "DetailsSummary"})

    time = []
    high_temperature = []
    low_temperature = []
    desc_weather = []
    percentage = []
    wind = []

    for data in ten_html_data:
        time.append(data.find("h3").text)
        try:
            high_temp = int(data.find("span", {"class": "DetailsSummary--highTempValue--3Oteu"}).text.replace("°", ""))
            high_temperature.append(fahrenheit_to_celcius(high_temp))
        except:
            high_temperature.append(None)

        try:
            low_temp = int(data.find("span", {"class": "DetailsSummary--lowTempValue--3H-7I"}).text.replace("°", ""))
            low_temperature.append(fahrenheit_to_celcius(low_temp))
        except:
            low_temperature.append(None)

        desc_weather.append(data.find("span", {"class": "DetailsSummary--extendedData--365A_"}).text)
        percentage.append(data.find("span", {"data-testid": "PercentageValue"}).text)
        wind.append(data.find("span", {"data-testid": "Wind"}).text)

    df = pd.DataFrame({
        "time": time,
        "high_temperature": np.array(high_temperature),
        "low_temperature": np.array(low_temperature),
        "desc_weather": desc_weather,
        "percentage": percentage,
        "wind": wind
    })

    return df

def dawn_water_temperature(atp_max, atp_min, ptp):
    """
    atp: air temperatur on the previous day
    ptp: pond temperature on the previous afternoon
    """
    return 2.218 + 0.062*atp_max + 0.285*atp_min + 0.561*ptp

def afternoon_water_temperature(ats_max, ats_min, pts):
    """
    ats: air temperature on the same day
    pts: pond temperature at dawn of the same day
    """
    return 2.071 - 0.068*ats_min + 0.651*pts + 0.373*ats_max

def air_to_pond_temperature(df, prev_temp):
    previous_low = []
    previous_heigh = []
    current_temp = []
    for x, y in df.iterrows():
        if x == 0:
            ptp_max, ptp_min, pts_max, pts_min = prev_temp, prev_temp, prev_temp, prev_temp
            atp = (ptp_max + ptp_min)/2
            ats = (pts_max + pts_min)/2
        else:
            high = y["high_temperature"]
            low = y["low_temperature"]
            ptp_max, ptp_min, pts_max, pts_min = previous_heigh[-1], previous_low[-1], high, low
            atp = (ptp_max + ptp_min)/2
            ats = (pts_max + pts_min)/2

        dawn = dawn_water_temperature(ptp_max, ptp_min, atp)
        noon = afternoon_water_temperature(pts_max, pts_min, ats)

        previous_low.append(min((dawn, noon)))
        previous_heigh.append(max((dawn, noon)))
        current_temp.append(np.mean((dawn, noon)))

    df["pond_low"] = previous_low
    df["pond_heigh"] = previous_heigh
    df["pond_temp"] = current_temp

    return df

#########################################
# feeding
#########################################
def feeding_expense(t, fc, biomassa, final_doc, formula_type=2, r=None):
    """
    r: feeding rate
    fc: feed cost per kg
    biomassa: biomassa in gr
    formula_type: formula_type for feeding cost expense calculation. There are 1 and 2.
    """
    if formula_type == 1:
        return biomassa / 1000 * r * fc
    else:
        formula3 = feed_formula3("data/data-feeding-formula-3.csv", ",")
        if t < final_doc:
            return (formula3[t] / 1000) * (1 + 0.2) * fc
        else:
            return 0


import matplotlib.patches as patches
import matplotlib.pyplot as plt
import numpy as np

def draw_bounding_box(image: np.ndarray, bounding_boxes) -> None:
    fig, ax = plt.subplots()
    ax.imshow(image)
    for b in bounding_boxes:
        y_min, x_min = b[0]
        y_max, x_max = b[1]
        box_width = x_max - x_min
        box_height = y_max - y_min
        rect = patches.Rectangle(
            (x_min, y_min),
            box_width,
            box_height,
            linewidth=2,
            edgecolor="g",
            facecolor="none",
        )
        ax.add_patch(rect)
    plt.show()

def draw_all_segments(img_rgb, segments):
    for s in segments:
        print(f"{s}, ", s.find_invariant_moments())
        print(s.find_bounding_points())
        draw_bounding_box(img_rgb, [s.find_bounding_points()])


from glycresoft_sqlalchemy.data_model import DatabaseManager, Hypothesis
from glycresoft_sqlalchemy.search_space_builder.glycopeptide_builder import integrated_omics
from .task_process import NullPipe, Message, Task
from ..common import get_random_string

def taskmain(database_path, hypothesis_name, protein_ids, protein_file, site_list_file,
             glycan_options, maximum_glycosylation_sites,
             comm=None, **kwargs):
    if comm is None:
        comm = NullPipe()
    manager = DatabaseManager(database_path)
    try:
        kwargs.setdefault("n_processes", 4)
        task = integrated_omics.IntegratedOmicsMS1SearchSpaceBuilder(
            database_path, hypothesis_name=hypothesis_name, mzid_path=protein_file, protein_ids=protein_ids,
            n_processes=kwargs["n_processes"], maximum_glycosylation_sites=maximum_glycosylation_sites,
            **glycan_options)
        hypothesis_id = task.start()
        if task.status != 0:
            raise task.error
        session = manager.session()
        hypothesis = session.query(Hypothesis).get(hypothesis_id)
        comm.send(Message(hypothesis.to_json(), "new-hypothesis"))
        return hypothesis_id
    except Exception:
        comm.send(Message.traceback())
        raise

class IntegratedOmicsGlycopeptideHypothesisBuilderTask(Task):
    def __init__(self, database_path, hypothesis_name, protein_ids, protein_file, site_list_file,
                 glycan_options, maximum_glycosylation_sites,
                 callback, **kwargs):
        args = (database_path, hypothesis_name, protein_ids, protein_file, site_list_file,
                glycan_options, maximum_glycosylation_sites)
        if hypothesis_name == "":
            hypothesis_name = get_random_string(10)
        job_name = "Integrated-Omics Glycopeptide Hypothesis Builder " + hypothesis_name
        kwargs.setdefault('name', job_name)
        super(IntegratedOmicsGlycopeptideHypothesisBuilderTask, self).__init__(taskmain, args, callback, **kwargs)


import datetime

from django import template
from django.conf import settings
from django.template.defaultfilters import stringfilter
from django.templatetags.static import static
from django.utils.translation import gettext_lazy as _

register = template.Library()

@register.simple_tag
def static_cdn(url):
    if settings.CDN_ENABLED:
        url = static(url).replace(settings.AWS_S3_CUSTOM_DOMAIN, settings.AWS_S3_CDN_DOMAIN).replace('/static/', '/')
        return url
    else:
        return static(url)

@register.simple_tag
def changelanguage(path, lang):
    if path and lang:
        if lang == 'en':
            newPath = path.replace("/tr/", "/en/")
            newPath = newPath.replace("profil", "profile")

        else:
            newPath = path.replace("/en/", "/tr/")
            newPath = newPath.replace("profile", "profil")
        return newPath
    else:
        return path

@register.filter
def to_br(value):
    return value.replace("<br>", "")

@register.filter
@stringfilter
def custom_date(value):
    now_time = datetime.datetime.now()

    now_time = datetime.datetime.strptime(str(now_time), '%Y-%m-%d %H:%M:%S.%f').strftime('%Y-%m-%d %H:%M:%S')
    value = datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S%z').strftime('%Y-%m-%d %H:%M:%S')

    now_time = datetime.datetime.strptime(now_time, '%Y-%m-%d %H:%M:%S')
    value = datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S') + datetime.timedelta(hours=3)

    total_time = now_time - value
    total_time_days = total_time.days
    total_time_str = str(total_time)

    if total_time_days == 1:
        value = str(total_time_days) + " " + _("Gün")
    elif total_time_days < 1:
        value_hour = int(total_time_str.split(':')[0])
        if value_hour == 0:
            value_minute = int(total_time_str.split(':')[1])
            if value_minute == 0:
                value_second = int(total_time_str.split(':')[2])
                value = str(value_second) + " " + _("Saniye")
            else:
                value = str(value_minute) + " " + _("Dakika")
        else:
            value = str(value_hour) + " " + _("Saat")

    elif total_time_days > 1:
        value = value
    else:
        value = value
    return str(value)

custom_date.is_safe = True


"""
Page models for Wagtail CMS.
"""

import urllib.parse

from django.conf import settings
from django.contrib import messages
from django.core.validators import MinLengthValidator
from django.db import models
from django.shortcuts import redirect, render
from modelcluster.contrib.taggit import ClusterTaggableManager
from modelcluster.fields import ParentalKey
from taggit.models import TaggedItemBase
from wagtail.admin.panels import FieldPanel, InlinePanel, MultiFieldPanel
from wagtail.contrib.routable_page.models import RoutablePageMixin, path
from wagtail.fields import RichTextField
from wagtail.models import Page
from wagtail.search import index
from wagtail.search.models import Query
from wagtail.snippets.models import register_snippet

from accounts.models import UserProfile

from .edit_handlers import AuthorPanel
from .paginator import paginate_posts
from .validators import validate_twitter_handle

class BlogIndexPage(RoutablePageMixin, Page):
    """
    Root page representing the blog's home, /blog/.

    Responsible for serving search and taggable results via routable sub-URLs through
    ``search_results()`` and ``tag_results()``, respectively. On the default route, it
    gets and serves the latest three blog posts, from every ``CategoryIndexPage``.
    """

    intro = RichTextField(
        help_text="Brief page description used in the intro section."
    )

    content_panels = Page.content_panels + [
        FieldPanel("intro", classname="full"),
    ]

    max_count = 1  # Singleton class

    subpage_types = ["CategoryIndexPage"]

    @path("search/", name="search")
    def search_results(self, request):
        """
        Logs the query and processes the user's search request.
        Search results are returned as a paginator.
        """
        search_query = request.GET.get("q", None)
        if search_query:
            query = Query.get(search_query)
            query.add_hit()

        results = paginate_posts(
            request,
            queryset=BlogPage.objects.live()
            .order_by("-date")
            .search(search_query),
        )

        return self.render(
            request,
            context_overrides={
                "query": search_query,
                "posts": results,
                "search": True,
            },
            template="blog/search_results.html",
        )

    @path("tags/", name="tag_results")
    def tag_results(self, request):
        """
        Get all posts under a given tag.
        Tag results are returned as a paginator.
        """
        tag = request.GET.get("tag")
        results = paginate_posts(
            request,
            queryset=BlogPage.objects.live()
            .order_by("-date")
            .filter(tags__name=tag),
        )

        return self.render(
            request,
            context_overrides={
                "tag": tag,
                "posts": results,
                "tag_filter": True,
            },
            template="blog/tag_results.html",
        )

    def get_context(self, request, *args, **kwargs):
        """
        Provides additional context for the default route only, /blog/.

        Get the latest three posts from every category, returned as a list
        of dictionaries.
        """
        context = super().get_context(request)
        if (
            request.path.strip("/") == self.slug
        ):  # Only apply to the blog home, /blog/.
            context["posts_per_category"] = [
                {
                    "category": category,
                    "posts": category.specific.get_recent_posts(),
                }  # returns 3 posts each
                for category in self.get_children().live()
            ]

        return context

class CategoryIndexPage(Page):
    """
    Represents category pages of the blog, /blog/category/.

    Responsible for serving all posts, ``BlogPage``, associated with the category.
    """

    intro = RichTextField(
        help_text="Brief page description used in the intro section."
    )

    content_panels = Page.content_panels + [
        FieldPanel("intro", classname="full"),
    ]

    parent_page_types = ["BlogIndexPage"]
    subpage_types = ["BlogPage"]

    def get_context(self, request, *args, **kwargs):
        """
        Add all posts associated with the category to context.
        The categories posts are returned as a paginator.
        """
        context = super().get_context(request)
        posts = paginate_posts(
            request,
            BlogPage.objects.child_of(self)
            .live()
            .specific()
            .order_by("-date"),
        )
        context["posts"] = posts
        return context

    def get_recent_posts(self):
        """
        Allows ``BlogIndexPage`` to get recent posts from every category.
        :return: The three most recent posts from the category, ordered by -date.
        :rtype: queryset
        """
        return (
            BlogPage.objects.child_of(self)
            .live()
            .specific()
            .order_by("-date")[:3]
        )

    class Meta:
        verbose_name_plural = "Blog categories"

class BlogPageTag(TaggedItemBase):
    """
    Attaches tagging to ``BlogPage``.
    """

    content_object = ParentalKey(
        "blog.BlogPage", related_name="tagged_items", on_delete=models.CASCADE
    )

class BlogPage(Page):
    """
    Represents blog posts, /blog/category/post.

    ``author`` must have an ``AuthorProfile``.
    """

    date = models.DateField("Post date")
    snippet = models.CharField(
        max_length=200, help_text="Excerpt used in article list preview card."
    )
    body = RichTextField(blank=True)
    tags = ClusterTaggableManager(through=BlogPageTag, blank=True)
    featured_image = models.ForeignKey(
        "wagtailimages.Image", on_delete=models.CASCADE
    )
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.PROTECT
    )
    featured_article = models.BooleanField(default=False)

    content_panels = Page.content_panels + [
        MultiFieldPanel(
            [
                FieldPanel("date"),
                FieldPanel("tags"),
            ],
            heading="Blog Information",
        ),
        FieldPanel("snippet"),
        FieldPanel("featured_image"),
        FieldPanel("body"),
        AuthorPanel("author"),
        InlinePanel("page_comments", label="Comments"),
    ]

    search_fields = Page.search_fields + [index.SearchField("body")]

    parent_page_types = ["CategoryIndexPage"]
    subpage_types = []

    def serve(self, request, *args, **kwargs):
        """
        Handle POST request for blog comments, ``BlogComment``.
        """
        from .forms import CommentForm

        if request.method == "POST":
            form = CommentForm(request.POST)
            if form.is_valid():
                new_comment = form.save(commit=False)
                new_comment.user = request.user
                new_comment.page = self
                new_comment.save()
                messages.success(
                    request,
                    "Your message was successfully "
                    "submitted and is awaiting moderation. "
                    "Thank you for contributing!",
                )
                return redirect(self.get_url(request))
        else:
            form = CommentForm

        return render(
            request, "blog/blog_page.html", {"page": self, "form": form}
        )

    @property
    def get_tags(self):
        """
        Returns all tags related to the blog post and sets the absolute url
        for each tag.

        :return: list of tags associated with the blog post.
        :rtype: list
        """
        tags = self.tags.all()
        base_url = self.get_site().root_page.url
        for tag in tags:
            tag.url = f"{base_url}tags/?tag={tag.name}"
        return tags

    def get_twitter_share_url(self):
        """
        :return: Formatted URL to share the article on Twitter.
        """
        base_url = "https://twitter.com/share?url="
        return f"{base_url}{self.full_url}&via=BrandishSEO"

    def get_facebook_share_url(self):
        """
        :return: Formatted URL to share the article on Facebook.
        """
        base_url = "https://www.facebook.com/sharer/sharer.php?u="
        return f"{base_url}{self.full_url}"

    def get_linkedin_share_url(self):
        """
        :return: Formatted URL to share the article on LinkedIn.
        """
        base_url = "https://www.linkedin.com/shareArticle?mini=true&url="
        return f"{base_url}{self.full_url}"

    def get_email_share_url(self):
        """
        :return: Formatted URL to send an email containing the article.
        """
        base_url = "mailto:?"
        email_title = urllib.parse.quote(f"Check this out: {self.title}")
        email_body = urllib.parse.quote(f"{self.snippet}: {self.full_url} ")
        return f"{base_url}subject={email_title}&body={email_body}"

@register_snippet
class BlogComment(models.Model):
    """
    Represents comments a user can post to a corresponding ``BlogPage``.

    NOTE: By default, ``is_approved`` is set to False. Thus, all comments must be
    manually approved before they will appear on the post.
    """

    page = ParentalKey(
        "BlogPage", on_delete=models.CASCADE, related_name="page_comments"
    )
    text = models.TextField(
        validators=[
            MinLengthValidator(3, "Comment must be greater than 3 characters.")
        ]
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT,
        related_name="comment_author",
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_approved = models.BooleanField(default=False)

    panels = [
        FieldPanel("page"),
        FieldPanel("text"),
        FieldPanel("user"),
        FieldPanel("is_approved"),
    ]

    def __str__(self):
        text = (
            self.text if len(str(self.text)) < 15 else self.text[:15] + "..."
        )
        return f"'{text}' on Page: '{self.page}'"

@register_snippet
class AuthorProfile(UserProfile):
    """
    Add the attribute ``bio`` to ``UserProfile``.
    """

    bio = models.TextField(
        validators=[
            MinLengthValidator(20, "Bio must be greater than 20 characters.")
        ]
    )
    twitter_handle = models.CharField(
        max_length=16,
        validators=[MinLengthValidator(5), validate_twitter_handle],
    )

    def __str__(self):
        return f"{self.user.first_name} {self.user.last_name}"


# use instead !!!
# pip install enasearch
# it useless!!!!!

"""
For wgs_set
"""
import requests
import json
import enasearch

base_url = "https://www.ebi.ac.uk/ena/portal/api/links"
# url_template = f"{base_url}/sample?accession=ERS3641673&format=JSON&result=wgs_set"

def ena_sample(sample_id,result='wgs_set'):

    url = f"{base_url}/sample?accession={sample_id}&format=JSON&result={result}"
    response = requests.get(url, )
    return response

def sample2wgs(sample_id):
    response = ena_sample(sample_id,result='wgs_set')
    if response.status_code != 200:
        return ''
    else:
        out = response.text
        data = json.loads(out)
        return data[0]

def sample2assembly(sample_id):
    response = ena_sample(sample_id,result='assembly')
    if response.status_code != 200:
        return ''
    else:
        out = response.text
        data = json.loads(out)
        return data[0]

data = enasearch.search_data(
    free_text_search=True,
    query="CABMLH010000000",
    result='wgs_set',
    display='xml'
)
data = enasearch.retrieve_data(
    ids="CABMLH010000000",
    display="html")

def get_returnable_fields(result):
    url = f"https://www.ebi.ac.uk/ena/portal/api/returnFields?dataPortal=ena&format=json&result={result}"
    response = requests.get(url, )
    out = response.text
    data = json.loads(out)
    return data
returnable_fields = get_returnable_fields('wgs_set')
returnable_fields = [_['columnId'] for _ in returnable_fields]

def file_report(sample_id):
    fields = ','.join(returnable_fields)
    url = f"https://www.ebi.ac.uk/ena/portal/api/filereport?accession={sample_id}&fields={fields}&format=json&result=wgs_set"
    response = requests.get(url, )
    out = response.text
    data = json.loads(out)
    return data

returnable_fields_assembly = get_returnable_fields('assembly')
returnable_fields_assembly = [_['columnId'] for _ in returnable_fields_assembly]

def file_report_assembly(sample_id):
    fields = ','.join(returnable_fields_assembly)
    url = f"https://www.ebi.ac.uk/ena/portal/api/filereport?accession={sample_id}&fields={fields}&format=json&result=assembly"
    response = requests.get(url, )
    out = response.text
    data = json.loads(out)
    return data

from tqdm import tqdm
s2info = {}
record_failed = []
for _ in tqdm(t):
    try:
        s2info[_] = file_report(_)
    except:
        record_failed.append(_)
cmds = []
for acc,_dict in s2info.items():
    url = _dict[0]['fasta_file']
    name = url.split('/')[-1]
    cmd = f"wget {url} -O ./rawdata/extra_data/fna/{name}"
    cmds.append(cmd)
from subprocess import check_call
for cmd in cmds:
    check_call(cmd,shell=1)

s2assembly_info = {}
for _f in record_failed:
    s2assembly_info[_f] = file_report_assembly(_f)


from datetime import datetime
from typing import Union
from source.abstracto.Expresion import Expresion
from source.expresiones.Acceso import Acceso
from source.abstracto.Instruccion import Instruccion
from source.abstracto.Retorno import Retorno, RetornoTraduccion, Tipo, TipoDato, TipoVariable
from source.consola_singleton.Consola import Consola
from source.errores.Excepcion import Excepcion
from source.expresiones.Primitivos import Primitivos
from source.instrucciones.Asignacion import Asignacion
from source.instrucciones.AsignacionVec import AsignacionVec
from source.instrucciones.Declaracion import Declaracion
from source.instrucciones.funcion.AsignacionParametros import AsignacionParametros
from source.instrucciones.funcion.Function import Function
from source.instrucciones.sentencias_de_transferencia.Return import Return
from source.simbolo.Simbolo import Simbolo, SimboloTraduccion, TiposSimbolos
from source.simbolo.TablaSimbolos import TablaSimbolos

class LlamadaFunction(Expresion):

    def __init__(self, idFuncion:str, insEntraParam:list[Expresion], line: int, column: int):
        super().__init__(line, column)
        self.idFuncion = idFuncion
        self.insEntraParam = insEntraParam
        #fase 2
        self.retornoLlamada:RetornoTraduccion = None

    def ejecutar(self, ts: TablaSimbolos):
        print("LLAMAN")
        consolaGlobal = Consola()
        simboloFuncion : Simbolo = ts.buscar(self.idFuncion)
        # validar que todo este bien antes de llamar a la funcion
        if simboloFuncion is None:
            consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, funcion sin declarar", self.line, self.column, datetime.now()))
            return Retorno("Error", TipoDato.ERROR, TipoVariable.NORMAL)

        if simboloFuncion.tipoSimbolo != TiposSimbolos.FUNCTION:
            consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, el nombre pertenece a otro tipo que no es funcion", self.line, self.column, datetime.now()))
            return Retorno("Error", TipoDato.ERROR, TipoVariable.NORMAL)

        funcionLLamada : Function = simboloFuncion.valor
        # NUEVO AMBITO PARA LA FUNCION LLAMADA
        newEnviromentFunction = TablaSimbolos(ts, "FUNCION_"+self.idFuncion+"-")

        # validar que la cantidad de parametros sea la misma
        if len(funcionLLamada.insParamFunc) != len(self.insEntraParam):
            consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, la cantidad de parametros no coincide", self.line, self.column, datetime.now()))
            return Retorno("Error", TipoDato.ERROR, TipoVariable.NORMAL)

        #           ASIGNACION DE PARAMETROS
        # validar que los tipos de parametros sean los mismos y que no existan errores.
        # Esto se hace reutilizando código de la clase Declaracion.py
        # luego Asignacion.py
        if len(funcionLLamada.insParamFunc) > 0:
            for i in range(len(funcionLLamada.insParamFunc)):
                parametroFuncion : Declaracion = funcionLLamada.insParamFunc[i]
                parametroLlamada : Expresion = self.insEntraParam[i]

                # Declarando el parametro en la tabla de simbolos de la funcion
                retornoParametroFuncion = parametroFuncion.ejecutar(newEnviromentFunction)

                if isinstance(retornoParametroFuncion, Excepcion):
                    # ERROR
                    consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, un parametro no se puede asignar", self.line, self.column, datetime.now()))
                    return Retorno("Error", TipoDato.ERROR, TipoVariable.NORMAL)

                # Asignando el parametro en la tabla de simbolos de la funcion
                asignacionParametroFuncion : AsignacionParametros = AsignacionParametros(parametroFuncion.id, parametroLlamada)
                retornoAsignacion = asignacionParametroFuncion.ejecutar(newEnviromentFunction, ts)
                if isinstance(retornoAsignacion, Excepcion):
                    # ERROR
                    consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, un parametro no se puede asignar", self.line, self.column, datetime.now()))
                    return Retorno("Error", TipoDato.ERROR, TipoVariable.NORMAL)
        #          FIN ASIGNACION DE PARAMETROS

        #           EJECTUAR INSTRUCCIONES DE LA FUNCION
        # ESTAS INSTRUCCIONES ESTAN EN EL ENTORNO GLOBAL -> ENTORNO DE LA FUNCION (para agarrar sus parametros)
        # Para esto se crea un entorno auxiliar con el entorno global como padre y el entorno de los parametro como anterior
        newEnviromentFunctionAux = newEnviromentFunction
        newEnviromentFunctionAux.anterior = funcionLLamada.entornoGlobal

        if len(funcionLLamada.insEntraFunc) > 0:
            for i in range(len(funcionLLamada.insEntraFunc)):
                instruccionFuncion : Instruccion = funcionLLamada.insEntraFunc[i]
                retornoInstruccion : Union[Excepcion, Return, None] = instruccionFuncion.ejecutar(newEnviromentFunctionAux)

                if isinstance(retornoInstruccion, Excepcion):
                    # ERROR
                    consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, una instruccion no se puede ejecutar", self.line, self.column, datetime.now()))
                    return Retorno("Error", TipoDato.ERROR, TipoVariable.NORMAL)

                if isinstance(retornoInstruccion, Return):
                    expresionRetornada : Expresion = retornoInstruccion.expresionReturn
                    if expresionRetornada == None:
                        return Retorno(None, TipoDato.NULL, TipoVariable.NORMAL)

                    if not isinstance(expresionRetornada, Expresion):
                        # ERROR
                        consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, el retorno de la funcion tiene errores", self.line, self.column, datetime.now()))
                        return Retorno("Error", TipoDato.ERROR, TipoVariable.NORMAL)

                    # si todo sale bien, yeiii se retorna la expresion para lo que se quiera.
                    retExpRetonarda : Retorno = expresionRetornada.ejecutar(newEnviromentFunction)
                    if retExpRetonarda.tipo == TipoDato.ERROR:
                        # ERROR
                        consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, el retorno de la funcion tiene errores", self.line, self.column, datetime.now()))
                        return Retorno("Error", TipoDato.ERROR, TipoVariable.NORMAL)

                    return retExpRetonarda
        return Retorno(None, TipoDato.NULL, TipoVariable.NORMAL)

    def graficarAst(self):
        consola = Consola()
        nombreNodo = f"instruccion_{self.line}_{self.column}_{str(id(self))}_"
        consola.set_AstGrafico(f"{nombreNodo}[label=\"\\<Instruccion\\>\\nLlamada Funcion [{self.idFuncion}]\"];\n")
        nombreNodoParametros = f"instruccion_{self.line}_{self.column}_{str(id(self))}_parametro_"
        consola.set_AstGrafico(f"{nombreNodoParametros}[label=\"\\<Expresion\\>\\nParametros\"];\n")
        consola.set_AstGrafico(f"{nombreNodo}->{nombreNodoParametros};\n")
        # PARAMETROS
        cont = 0
        nombreNodoAnterior = ""

        for instruccion in self.insEntraParam:
            try:
                if cont == 0:
                    nombreNodoAnterior = instruccion.graficarAst()
                    consola.set_AstGrafico(f"{nombreNodoParametros}->{nombreNodoAnterior};\n")
                else:
                    nombreNodoNuevo = instruccion.graficarAst()
                    consola.set_AstGrafico(f"{nombreNodoAnterior}->{nombreNodoNuevo};\n")
                    nombreNodoAnterior = nombreNodoNuevo

            except Exception as error:
                print("soy un error en llamada funcion -> parametros de funcion ast: " + error)
            cont += 1
        return nombreNodo

    def traducir(self, ts: TablaSimbolos):
        consolaGlobal: Consola = Consola()
        cadenaRetorno = ""
        simboloFuncion : SimboloTraduccion = ts.buscar(self.idFuncion)
        # validar que todo este bien antes de llamar a la funcion
        if simboloFuncion is None:
            consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, funcion sin declarar", self.line, self.column, datetime.now()))
            return RetornoTraduccion(valor="Error",
                                         tipo=TipoDato.ERROR,
                                         tipoVariable=TipoVariable.NORMAL)

        if simboloFuncion.tipoSimbolo != TiposSimbolos.FUNCTION:
            consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, el nombre pertenece a otro tipo que no es funcion", self.line, self.column, datetime.now()))
            return RetornoTraduccion(valor="Error",
                                         tipo=TipoDato.ERROR,
                                         tipoVariable=TipoVariable.NORMAL)

        funcionLLamada : Function = simboloFuncion.temporal
        # si y solo si la función no ha sido traducida al ser llamada.
        if not funcionLLamada.funcionTraducida:
            funcionLLamada.funcionTraducida = True
            funcionLLamada.entornoGlobal.actualizarVariable(funcionLLamada.id, funcionLLamada)
            # DECLARACION DE PARAMETROS
            # declaración de parametros necesaria para escribir la función.
            # Pero esta declaracion no se añade al código de traducción devuelto
            if len(funcionLLamada.insParamFunc) > 0:
                for i in range(len(funcionLLamada.insParamFunc)):
                    parametroFuncion : Declaracion = funcionLLamada.insParamFunc[i]
                    # Declarando el parametro en la tabla de simbolos de la funcion
                    retornoParametroFuncion:str = parametroFuncion.traducir(funcionLLamada.entornoFuncion)

                    if isinstance(retornoParametroFuncion, Excepcion):
                        # ERROR
                        consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, un parametro no se puede asignar", self.line, self.column, datetime.now()))
                        return RetornoTraduccion(valor="Error",
                                         tipo=TipoDato.ERROR,
                                         tipoVariable=TipoVariable.NORMAL)

            for simbolo in funcionLLamada.entornoFuncion.tablaActual:
                valor:SimboloTraduccion = funcionLLamada.entornoFuncion.tablaActual[simbolo]
                if valor.tipoDato == TipoDato.NULL:
                    aux : Tipo = valor.tipo
                    valor.tipoDato = consolaGlobal.getTipoDato(aux)
                print(str(valor))

            # GENERACIÓN DE CÓDIGO DE INSTRUCCIONES DE LA FUNCIÓN
            funcionLLamada.etqSalida = consolaGlobal.genNewEtq()
            funcionLLamada.etqReturn = funcionLLamada.etqSalida
            consolaGlobal.codigo3dFunciones2[funcionLLamada.id] = "func {}(){{\n".format(funcionLLamada.id)
            for ins in funcionLLamada.insEntraFunc:
                ins.etqReturn = funcionLLamada.etqReturn
                resIn = ins.traducir(funcionLLamada.entornoFuncion)

                if isinstance(resIn, Excepcion):
                    return RetornoTraduccion(valor="Error",
                                         tipo=TipoDato.ERROR,
                                         tipoVariable=TipoVariable.NORMAL)

                if isinstance(resIn, RetornoTraduccion):
                    consolaGlobal.codigo3dFunciones2[funcionLLamada.id] += resIn.codigoTraducido
                else:
                    consolaGlobal.codigo3dFunciones2[funcionLLamada.id] += resIn

            consolaGlobal.codigo3dFunciones2[funcionLLamada.id] += consolaGlobal.genGoto(funcionLLamada.etqSalida)
            consolaGlobal.codigo3dFunciones2[funcionLLamada.id] += "{}:\n".format(funcionLLamada.etqSalida)
            consolaGlobal.codigo3dFunciones2[funcionLLamada.id] += "return;\n"
            consolaGlobal.codigo3dFunciones2[funcionLLamada.id] += "}\n\n"
            # actualizando los cambios de la tabla de simbolos de la funcion.
            funcionLLamada.funcionTraducida = True
            funcionLLamada.entornoGlobal.actualizarVariable(funcionLLamada.id, funcionLLamada)

        # NUEVO AMBITO PARA LA FUNCION LLAMADA
        newEnviromentFunction = TablaSimbolos(ts, "FUNCION_"+self.idFuncion+"-")
        inicioStackFuncion = newEnviromentFunction.size
        newEnviromentFunction.size += 1 # Se reserva el espacio para el return (0)

        # validar que la cantidad de parametros sea la misma
        if len(funcionLLamada.insParamFunc) != len(self.insEntraParam):
            consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, la cantidad de parametros no coincide", self.line, self.column, datetime.now()))
            return RetornoTraduccion(valor="Error",
                                         tipo=TipoDato.ERROR,
                                         tipoVariable=TipoVariable.NORMAL)

        # EMPEZANDO CUERPO FUNCION
        cadenaRetorno += consolaGlobal.genComment(f"INSTRUCCION DE LLAMADA DE FUNCION {funcionLLamada.id}")
        cadenaRetorno += consolaGlobal.genComment(f"DECLARACION Y ASIGNACION DE PARAMETROS {funcionLLamada.id}")

        #           ASIGNACION DE PARAMETROS
        # validar que los tipos de parametros sean los mismos y que no existan errores.
        # Esto se hace reutilizando código de la clase Declaracion.py
        # luego Asignacion.py
        if len(funcionLLamada.insParamFunc) > 0:
            for i in range(len(funcionLLamada.insParamFunc)):
                parametroFuncion : Declaracion = funcionLLamada.insParamFunc[i]
                # Declarando el parametro en la tabla de simbolos de la funcion
                retornoParametroFuncion:str = parametroFuncion.traducir(newEnviromentFunction)
                parametroLlamada : Expresion = self.insEntraParam[i]

                if isinstance(retornoParametroFuncion, Excepcion):
                    # ERROR
                    consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, un parametro no se puede asignar", self.line, self.column, datetime.now()))
                    return RetornoTraduccion(valor="Error",
                                         tipo=TipoDato.ERROR,
                                         tipoVariable=TipoVariable.NORMAL)
                cadenaRetorno += retornoParametroFuncion

                # una llamada de funcion como parametro
                if isinstance(self.insEntraParam[i], LlamadaFunction):
                    ts.size += len(funcionLLamada.insParamFunc)
                    # Asignando el parametro en la tabla de simbolos de la funcion
                    asignacionParametroFuncion : AsignacionParametros = AsignacionParametros(parametroFuncion.id, parametroLlamada)
                    retornoAsignacion = asignacionParametroFuncion.traducir(newEnviromentFunction, ts)
                    ts.size -= len(funcionLLamada.insParamFunc)
                # una variable o valor cualquiera como parametro
                else:
                    # Asignando el parametro en la tabla de simbolos de la funcion
                    asignacionParametroFuncion : AsignacionParametros = AsignacionParametros(parametroFuncion.id, parametroLlamada)
                    retornoAsignacion = asignacionParametroFuncion.traducir(newEnviromentFunction, ts)

                if isinstance(retornoAsignacion, Excepcion):
                    # ERROR
                    consolaGlobal.set_Excepcion(Excepcion("Error Semantico", "Error en la llamada de funcion, un parametro no se puede asignar", self.line, self.column, datetime.now()))
                    return RetornoTraduccion(valor="Error",
                                         tipo=TipoDato.ERROR,
                                         tipoVariable=TipoVariable.NORMAL)
                cadenaRetorno += retornoAsignacion
        #          FIN ASIGNACION DE PARAMETROS

        # me di cuenta que una forma de que todo funcione si es ejecutando y creando
        # las instrucciones en cada llamada esto por como trabajamos las nativas.
        #           EJECTUAR INSTRUCCIONES DE LA FUNCION
        # ESTAS INSTRUCCIONES ESTAN EN EL ENTORNO GLOBAL -> ENTORNO DE LA FUNCION (para agarrar sus parametros)
        # Para esto se crea un entorno auxiliar con el entorno global como padre y el entorno de los parametro como anterior
        # newEnviromentFunctionAux = newEnviromentFunction
        # newEnviromentFunctionAux.anterior = funcionLLamada.entornoGlobal
        # self.etqSalida = consolaGlobal.genNewEtq()
        # self.etqReturn = self.etqSalida
        # cadenaRetorno += consolaGlobal.genComment(f"INICIO INSTRUCCIONES FUNCION {funcionLLamada.id}")
        # for ins in funcionLLamada.insEntraFunc:
        #     ins.etqReturn = self.etqReturn
        #     resIn = ins.traducir(newEnviromentFunctionAux)

        #     if isinstance(resIn, Excepcion):
        #         return Excepcion()

        #     if isinstance(resIn, RetornoTraduccion):
        #         if self.retornoLlamada == None:
        #             self.retornoLlamada = resIn
        #             cadenaRetorno += resIn.codigoTraducido
        #             continue

        #     cadenaRetorno += resIn
        # cadenaRetorno += consolaGlobal.genComment(f"FIN INSTRUCCIONES FUNCION {funcionLLamada.id}")
        # cadenaRetorno += consolaGlobal.genGoto(self.etqSalida)
        # cadenaRetorno += "{}:\n".format(self.etqSalida)

        cadenaRetorno += consolaGlobal.genComment(f"moviendo puntero al ambito del stack de {funcionLLamada.id}")
        cadenaRetorno += consolaGlobal.genAsignacion("SP", "SP + {}".format(inicioStackFuncion))
        cadenaRetorno += "{}();\n".format(funcionLLamada.id)
        temporal = consolaGlobal.genNewTemp()
        temporal2 = consolaGlobal.genNewTemp()
        # Recuperando algún valor de retorno (RETURN)
        cadenaRetorno += consolaGlobal.genComment(f"obteniendo return funcion {funcionLLamada.id}")
        cadenaRetorno += consolaGlobal.genAsignacion(temporal, "SP + 0")
        cadenaRetorno += consolaGlobal.genAsignacion(temporal2,
                                   "STACK[int({})]".format(temporal))

        cadenaRetorno += consolaGlobal.genComment(f"restableciendo puntero al ambito anterior de {funcionLLamada.id}")
        cadenaRetorno += consolaGlobal.genAsignacion("SP", "SP - {}".format(inicioStackFuncion))

        #Reiniciando temporales de cada variable creada en la función.
        cadenaRetorno += consolaGlobal.genComment(f"reiniciando temporales funcion {funcionLLamada.id}")
        for contador, simbolo in enumerate(funcionLLamada.entornoFuncion.tablaActual):
                valor:SimboloTraduccion = funcionLLamada.entornoFuncion.tablaActual[simbolo]
                temporal = valor.temporal
                temporalAux = consolaGlobal.genNewTemp()
                cadenaRetorno += consolaGlobal.genAsignacion(temporalAux, f"SP + {contador+1}")
                cadenaRetorno += consolaGlobal.genAsignacion(valor.temporal,
                                   "STACK[int({})]".format(temporalAux))
                print("Valor {}: {}".format(contador, valor))

        # Se retorna el valor de llamada de la funcion.
        return RetornoTraduccion(valor=temporal2,
                                         tipo=funcionLLamada.tipoDatoFuncion,
                                         tipoVariable=funcionLLamada.tipoVariableFuncion,
                                         codigoTraducido=cadenaRetorno)


from typing import List

from copy import copy

def insertion_sort(data):
    data = copy(data)

    def insert(data, pos, val):
        i = pos - 1

        while i >= 0 and data[i] > val:
            data[i+1] = data[i]
            i -= 1
        data[i+1] = val

    for i in range(1, len(data)):
        insert(data, i, data[i])

    return data

def bubble_sort(data: List) -> List:
    data = copy(data)

    for _ in range(len(data)):
        for i in range(1, len(data)):
            if data[i-1] > data[i]:
                data[i-1], data[i] = data[i], data[i-1]

    return data

def quick_sort(data: List) -> List:
    data = copy(data)

    if len(data) < 2:
        return data

    middle = data[0]
    left = []
    right = []

    for i in data[1:]:
        if i < middle:
            left.append(i)
        else:
            right.append(i)
    left.append(middle)

    return quick_sort(left) + quick_sort(right)

def merge_sort(data: List) -> List:
    data = copy(data)

    if len(data) < 2:
        return data

    middle = int(len(data) / 2)

    left = merge_sort(data[:middle])
    right = merge_sort(data[middle:])

    return list(merge(left, right))

def merge(left: List, right: List):
    i = 0
    j = 0

    print('merge', left, right)

    while i < len(left) and j < len(right):
        while left[i] < right[j]:
            yield left[i]
            i += 1

            if i == len(left):
                yield from right[j:]
                return

        while right[j] <= left[i]:
            yield right[j]
            j += 1

            if j == len(right):
                yield from left[i:]
                return


import sys
from collections import defaultdict
input = sys.stdin.readline

N = int(input())

line = []

for _ in range(N):
    line.append(input().rstrip())

atoi = defaultdict(lambda: 0)

for s in line:
    for i in range(len(s)):
        atoi[s[i]] += 10 ** (len(s) - i)

alpha2num = {}
i = 9
for k, v in sorted(atoi.items(), key=lambda x: x[1], reverse=True):
    alpha2num[k] = i
    i -= 1

total = 0
for s in line:
    total += int(''.join(str(alpha2num[a]) for a in s))
print(total)


'''
Created on Jul 25, 2017

@author: Himanshu Ranjan
'''
# This program finds the phone numbers and email address on the clipboard.
# would be useful if you have the boring task of finding every mail and phone number on a web page

import re
import pyperclip

# Step 1: Create a Regex for Phone Numbers

phoneRegex = re.compile(r'''(
    (\d{3}|\(\d{3}\))?                    # area code
    (\s|-|\.)?                            # separator
    (\d{3})                               #first 3 digits
    (\s|-|\.)                             # separator
    (\d{4})                               # last 4 digits
    (\s*(ext|x|ext.)\s*(\d{2,5}))?        # extension
#    )''')
#    )''', re.VERBOSE)

# Step 2: Create a Regex for Email addresses

emailRegex = re.compile(r'''(
    [a-zA-Z0-9._%+-]+                # username
    @                                # @ symbol
    [a-zA-Z0-9.-]+                   # domain name
    (\.[a-zA-Z]{2,4})                # dot-something
    )''')
#    )''', re.VERBOSE)

# Step3 : Find all the matches in the clipboard text

text = str(pyperclip.paste())
matches = []
for groups in phoneRegex.findall(text):
    phoneNum = '-'.join([groups[1], groups[3], groups[5]])
    if groups[8] != "":
        phoneNum += ' x' + groups[8]
    matches.append(phoneNum)

for groups in emailRegex.findall(text):
    matches.append(groups[0])

# Step 4: Join the matches into a string for the clipboard

if len(matches)>0:
    pyperclip.copy('\n'.join(matches))
    print('Copied to clipboard:')
    print('\n'.join(matches))
else:
    print('No phone numbers or email addresses found.')


import json
d = dict(name='Bob', age=20, score=88)

# write_1
f = open('json.json', 'w')
json.dump(d, f)
f.close()

# write_2
print(json.dumps(d))
print()

# read_1
f = open('json.json', 'r')
r = json.load(f)
f.close()
print(r)
print()

# read_2
json_str = '{"name": "Bob", "age": 20, "score": 88}'
print(json.loads(json_str))


import asyncpg
import logging

from pydantic import PostgresDsn

from mongo_vs_postgres.postgres import queries
from mongo_vs_postgres.core.decorators import timeit
from mongo_vs_postgres.base_storage import AsyncBaseStorage

logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

class AsyncPostgresStorage(AsyncBaseStorage):
    _conn = None

    def __init__(self, dsn: PostgresDsn):
        self._dsn = dsn

    def __repr__(self):
        return "Postgres"

    @property
    def id_column(self) -> str:
        return "id"

    async def init_connection(self):
        self._conn = await asyncpg.connect(self._dsn)

    @timeit
    async def insert(self, table: str, params: dict) -> None:
        if not params:
            return
        columns = "(" + ",".join(params.keys()) + ")"
        values = convert_to_pg_values(params)
        await self._conn.execute(
            queries.INSERT.format(
                table=table,
                columns=columns
            ) + values
        )

    @timeit
    async def find(self, table: str, params: dict) -> list[dict]:
        query = queries.SELECT_WHERE.format(table=table) + convert_to_pg_condition(params)
        data = await self._conn.fetch(query)
        return data

    @timeit
    async def delete(self, table: str, params: dict) -> None:
        query = queries.DELETE_WHERE.format(table=table) + convert_to_pg_condition(params)
        await self._conn.execute(query)

    async def drop_db(self) -> None:
        await self._conn.execute(queries.DROP_ALL_TABLES)

    async def create_tables(self) -> None:
        for query in queries.CREATE_TABLES:
            await self._conn.execute(query)

def convert_to_pg(value: str | int) -> str:
    if isinstance(value, str):
        return f"'{value}'"
    if value.isdigit():
        return str(value)

def convert_to_pg_values(params: dict) -> str:
    data = [convert_to_pg(v) for v in params.values()]
    return "(" + ",".join(data) + ")"

def convert_to_pg_condition(params: dict) -> str:
    return " AND ".join(
        [f"{k} = {convert_to_pg(v)}" for k, v in params.items()]
    )


import pymongo  # ORM
from pymongo import MongoClient
from bson.json_util import dumps,RELAXED_JSON_OPTIONS
import json
import time
from flask import Flask, session, request, jsonify, g
from utils import add_log # import adding logs function from utils.py
from flask_cors import CORS

app = Flask(__name__)
CORS(app)
mongo_uri = "mongodb://localhost:27017/"
client = pymongo.MongoClient(mongo_uri)

# Get all books
@app.route('/allbooks',methods=["GET"])
def get_allbooks_paginated():
    db = client['meta']
    col= db['newmetadata']
    page = request.args.get('page')
    if page == None:
        page = 2
    page = int(page)
    response = col.find().skip(page).limit(8)
    #return {'message':"found","books":str(list(response))},201
    return dumps(response)

# Get one book
# asin -- make sure not in form of a string
@app.route('/metadata/<asin>', methods=['GET'])
def query_meta(asin):
    db = client['meta'] # change to meta from MetaData for EC2
    collection = db['newmetadata'] # change to newmetadata from metadata for EC2
    v = collection.find_one({"asin": asin})
    try:
        if asin == v["asin"]:
            # returns the metadata for particular book
            return {'message': "Book's metadata exists", 'data': str(v)}, 201
    except:
        return {'message': "Book's metadata does not exists", 'data': {}}, 404

# Add a new book -- needs everything from frontend (asin & title & price & category)
@app.route('/bookPost', methods=["POST"])
def post_books():
    asin = request.args.get('asin')
    title = request.args.get('title')
    price = request.args.get('price')
    category = request.args.get('category')

    db = client['meta']
    collection = db['newmetadata']
    collection1 = db['logs'] # Collection for logs -- create one in EC2 instance

    v = collection.find_one({"asin": asin})
    try:
        if asin == v["asin"]:
            response_code = 404
            add_log(request.method, request.url,{"book_information": {"title": title, "price": price, "category": category}}, response_code, collection1)
            return {'message': 'Book exists. Please select another one!', 'data': {}}, 404
    except:
        # add into metadata collection
        post_id = collection.insert_one(request.args.to_dict())
        vv = collection.find_one({"asin": asin})
        response_code = 201
        # add into logs collection
        add_log(request.method, request.url,{"book_information": {"title": title, "price": price, "category": category}}, response_code, collection1)
        return {'message': 'Book added', 'data': str(vv)}, 201

# searches for a book - need page & EITHER title OR author OR category
@app.route('/bookSearch', methods=["GET"])
def search_books():
    page = request.args.get('page')
    if page == None:
        page = 2
    page = int(page)

    db = client['meta']
    collection = db['newmetadata']
    collection1 = db['logs']
    if(request.args.get("title") != None):
        mytitle = request.args.get("title")
        v = collection.find_one({"title":{'$regex': mytitle, '$options': 'i'}})
        if v != None:
            response_code=201
            add_log(request.method, request.url,{"book_information": {"title searched": request.args.get("title")}}, response_code, collection1)
            return dumps(v)
        else:
            response_code=404
            add_log(request.method, request.url,{"book_information": {"title searched": request.args.get("title")}}, response_code, collection1)
            return {'message': 'Book does not exists!', 'data': {}}, 404
    if(request.args.get("author") != None):
        myauthor = request.args.get("author")
        v = collection.find({"author":{'$regex': myauthor, '$options': 'i'}}) # add .skip(page).limit(8)
        if v != None:
            response_code=201
            add_log(request.method, request.url,{"book_information": {"author searched": request.args.get("title")}}, response_code, collection1)
            return dumps(v)
        else:
            response_code=404
            add_log(request.method, request.url,{"book_information": {"author searched": request.args.get("title")}}, response_code, collection1)
            return {'message': 'Book does not exists!', 'data': {}}, 404
    if(request.args.get("category") != None):
        v = collection.find({"categories": {"$elemMatch":{"$elemMatch":{"$in":[request.args.get("category")]}}}}).skip(page).limit(8)
        if(v.count() == 0):
            response_code=404
            add_log(request.method, request.url,{"book_information": {"category searched": request.args.get("category")}}, response_code, collection1)
            return {'message': 'Book does not exists!', 'data': {}}, 404
        if(v != None):
            response_code=201
            add_log(request.method, request.url,{"book_information": {"category searched": request.args.get("category")}}, response_code, collection1)
            return dumps(v)
    else:
        return {'message': "Error"}, 404

# Deleting a book -- need asin
@app.route('/metadelete', methods=['DELETE'])
def delete_record():
    db = client['meta']
    collection= db['newmetadata']
    collection1 = db['logs']

    asin1 = request.args.get('asin')
    v = collection.find_one({"asin": asin1})
    try:
        if asin1 == v["asin"]:
            collection.remove({"asin": asin1})
            response_code = 201
            add_log(request.method, request.url,{"book deleted": str(v)}, response_code, collection1)
            return {'message': 'Deleted metadata of book', 'data': str(v)}, 201
    except:
        response_code = 404
        add_log(request.method, request.url, {"book does not exist so not deleted": asin1}, response_code, collection1)
        return {'message': 'Book does not exist so cannot delete metadata', 'data': {}}, 404

#make searchbar dynamic
@app.route('/dynamicSearch',methods=["GET"])
def dynamic_search():
    db = client['meta']
    collection= db['newmetadata']
    search_query = request.args.get('author')
    res = collection.find({"$text": {"$search": search_query}})
    if res != None:
            response_code=201
            return dumps(res)
    else:
        return {'message': 'Book does not exists!', 'data': {}}, 404

if __name__ == "__main__":
    app.run()


import torch
import torch.nn as nn

class AutoEncoderUnet(nn.Module):
    def __init__(self, chnum_in):
        super(AutoEncoderUnet, self).__init__()
        print('AutoEncoderUnet')

        self.chnum_in = chnum_in
        feature_num = 64
        feature_num_x2 = 128
        feature_num_fc = 9216
        label_num = 10
        num_layers = 4

        self.layer1 = nn.Sequential(
            nn.Conv2d(in_channels = self.chnum_in, out_channels = feature_num, kernel_size=3),
            nn.BatchNorm2d(feature_num),
            nn.ReLU()
        )
        self.layer2 = nn.Sequential(
            nn.Conv2d(in_channels = feature_num, out_channels = feature_num, kernel_size=3),
            nn.BatchNorm2d(feature_num),
            nn.ReLU()
        )
        self.layer3 = nn.Sequential(
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Dropout(0.5),
            nn.Flatten(),
            nn.Linear(feature_num_fc, feature_num_x2),
            nn.ReLU()
        )
        self.layer4 = nn.Sequential(
            nn.BatchNorm1d(feature_num_x2),
            nn.Dropout(0.5),
            nn.Linear(feature_num_x2, label_num)
        )

    def forward(self, x):
        funcs = []
        out1 = self.layer1(x)
        out2 = self.layer2(out1)
        out3 = self.layer3(out2)
        out4 = self.layer4(out3)
        funcs.append(out1)
        funcs.append(out2)
        funcs.append(out3)
        funcs.append(out4)

        # print(funcs[1].shape)
        return funcs


#!/usr/bin/evn python3
#Author: mike4192 https://github.com/mike4192/spotMicro

import numpy as np
import tf
from . StateCommand import State, Command, BehaviorState
from . TrotGaitController import TrotGaitController

class Robot(object):

    def __init__(self, body, legs, imu):
        self.body = body
        self.legs = legs

        self.delta_x = self.body[0] * 0.5
        self.delta_y = self.body[1] * 0.5 + self.legs[1]
        self.x_shift_front = 0.006
        self.x_shift_back = -0.03
        self.default_height = 0.15

        self.trotGaitController = TrotGaitController(self.default_stance,
            stance_time = 0.18, swing_time = 0.34, time_step = 0.02,
            use_imu = imu)

        self.currentController = self.trotGaitController

        # reconfigure state
        self.state = State(self.default_height)
        self.state.foot_locations = self.default_stance
        self.state.behavior_state = BehaviorState.TROT
        self.state.ticks = 0

        self.currentController.pid_controller.reset()
        self.command = Command(self.default_height)

    def joystick_command(self,msg):
        self.currentController.updateStateCommand(msg, self.state, self.command)

    def imu_orientation(self,msg):
        q = msg.orientation
        rpy_angles = tf.transformations.euler_from_quaternion([q.x,q.y,q.z,q.w])
        self.state.imu_roll = rpy_angles[0]
        self.state.imu_pitch = rpy_angles[1]

    def run(self):
        return self.currentController.run(self.state, self.command)

    @property
    def default_stance(self):
        # FR, FL, RR, RL
        return np.array([[self.delta_x + self.x_shift_front,self.delta_x + self.x_shift_front,-self.delta_x + self.x_shift_back,-self.delta_x + self.x_shift_back],
                         [-self.delta_y                    ,self.delta_y                     ,-self.delta_y                    , self.delta_y                    ],
                         [0                                ,0                                ,0                                ,0                                ]])