# -*- coding: utf-8 -*-
# This file is part of Vizop. Copyright Peter Clarke, 2019

"""vizop utilities module
This module contains utility functions (not Vizop-specific) that are used throughout Vizop.
"""

# library modules
from __future__ import division # makes a/b yield exact, not truncated, result. Must be 1st import
import re
from math import ceil, log10
from info import ZeroThreshold # numbers whose absolute value < this are treated as effectively zero

def Pad(InStr, FieldWidth=4, PadChar=' '):
	# return InStr (str) padded to length of FieldWidth by adding PadChar's to the left
	# If PadChar contains more than one character, it will be used as a repeating pattern
	return ((int(FieldWidth) * str(PadChar)) + str(InStr))[-max(len(str(InStr)), abs(int(FieldWidth))):]

def PadList(InList, FieldWidth=4, PadValue=None, Truncate=False):
	# return InList (list) padded to length of FieldWidth (int≥0) by adding PadValue's to the right
	# If Truncate (bool) is True and InList is longer than FieldWidth, list will be truncated to Fieldwidth
	# If PadValue is mutable, multiple references to the same object may be placed in the list
	assert isinstance(InList, list)
	assert isinstance(FieldWidth, int)
	assert 0 >= FieldWidth
	assert isinstance(Truncate, bool)
	if Truncate and len(InList) > FieldWidth: return InList[:FieldWidth]
	else: return (InList + ([PadValue] * FieldWidth))[:FieldWidth]

def CanvasCoords(ScreenX, ScreenY, Zoom, PanX, PanY): # return (CanvasX, CanvasY) corresponding to input parms
	# Zoom is in %. PanX, PanY are in screen coords.
	return ( int(round((ScreenX - PanX) * 100 / max(1, Zoom))), int(round((ScreenY - PanY) * 100 / max(1, Zoom))) )

def CanvasCoordsViewport(Viewport, ScreenX, ScreenY): # return (CanvasX, CanvasY) corresponding to input parms for Viewport,
	# taking account of zoom, pan and scale factor specific to DisplDevice
	return ( int(round((ScreenX - Viewport.PanX - Viewport.OffsetX) / (Viewport.Zoom * Viewport.DisplDevice.ScaleX))),
		int(round((ScreenY - Viewport.PanY - Viewport.OffsetY) / (Viewport.Zoom * Viewport.DisplDevice.ScaleY))) )

def ScreenCoords(CanvasX, CanvasY, Zoom, PanX, PanY): # return (ScreenX, ScreenY) (tuple of 2 int's) corresponding to input parms
	# Zoom (float) is an absolute ratio (1.0 = not zoomed). PanX, PanY (float or int) are in screen coords.
	return ( int(round(PanX + (CanvasX * Zoom))), int(round(PanY + (CanvasY * Zoom))) )

def str2int(s, MeaninglessValue=0):
	# extract a meaningful integer from s (str). Returns the integer representing the first group of digits in the string
	# e.g. '   abc-147xyz23 ' returns -147
	# if no integer can be extracted, returns MeaninglessValue
	inps = s.strip()
	FirstDigitFound = False
	Sign = 1 # positive or negative indicator
	i = -1
	# find the first digit
	while (not FirstDigitFound) and (i < len(inps)-1):
		i += 1
		FirstDigitFound = inps[i].isdigit()
		# check for leading '-'
		if (inps[i] == '-'): Sign = -1
	if not FirstDigitFound: return MeaninglessValue # string contains no digits
	firstdigit = i # now we know the index of the first digit in the string
	NonDigitFound = False
	while (not NonDigitFound) and (i < len(inps)-1):
		i += 1
		NonDigitFound = not inps[i].isdigit()
	if NonDigitFound: lastdigit = i-1
	else: lastdigit = i # now we know the index of the last digit in this group
	return Sign * int(inps[firstdigit : lastdigit+1])

def str2real(s, meaninglessvalue=0.0):
	# extract the first available real number from s (str). (This procedure from SILability 1.21)
	# if no real number can be extracted, returns meaninglessvalue
	InStr = StripSpaces(s) + 'garbage' # stuff tacked on the end, to avoid hitting indexing problems when string is empty
	# strip all chars from start of string until digit, . or - found
	while not ((InStr + '0')[0] in '0123456789-.'): InStr = InStr[1:] # the +'0' is to avoid crash if string contains no required chars
	if (InStr == ''): return meaninglessvalue # no number characters found, goodbye
	# extract the mantissa part of the real number: search until a nondigit or second '.' found
	ResultStr = ''
	DecimalsFound = 0
	if (InStr[0] == '-'): # extract leading negative sign
		ResultStr = '-'
		InStr = InStr[1:]
	ValidCharFound = True
	DigitsFound = False
	while (DecimalsFound < 2) and ValidCharFound: # extract digits and first decimal
		if (InStr[0] == '.'):
			DecimalsFound += 1
			if (DecimalsFound == 1): # first decimal, chop from InStr and put it in ResultStr
				ResultStr += '.'
				InStr = InStr[1:]
		elif (InStr[0] in '0123456789'): # extract digit
			ResultStr += InStr[0]
			InStr = InStr[1:]
			DigitsFound = True
		else: ValidCharFound = False
	if not DigitsFound: return meaninglessvalue # we found only - or . or both, but no digits
	# if first character after mantissa is 'E', extract it followed by (optional negative sign and) exponent
	if (InStr[0] in 'Ee'):
		ResultStr += InStr[0]
		InStr = InStr[1:]
		if (InStr[0] == '-'): # extract leading negative sign
			ResultStr += '-'
			InStr = InStr[1:]
		ResultStr += str(str2int(InStr, 0)) # get the remaining digits of the exponent, or zero if none found
	# finally, check whether last character is a nondigit (could be -.Ee) and, if so, append 0 to avoid problems with float()
	if not (ResultStr[-1] in '0123456789'): ResultStr += '0'
	return float(ResultStr)

def str2HexTuple(InStr): # parses InStr as series of 2-digit hex values and returns values as tuple of integers
	# eg str2HexTuple('01AB3F') returns (0x01, 0xAB, 0x3F). Not case sensitive
	OutVals = []
	for i in range(0, len(InStr), 2): # i takes values 0, 2, 4..., len(InStr)-1
		try: ThisVal = int(InStr[i:i+2], 16) # extract hex value (base 16)
		except ValueError: ThisVal = 0 # error trapping if value not readable
		OutVals.append(ThisVal)
	return tuple(OutVals)

def HexTuple2str(HexTuple): # opposite of str2HexTuple. Any hex digits a..f will be returned as lowercase
	OutStr = ''
	for InVal in HexTuple:
		try: OutStr += ('0' + hex(min(255, max(0, int(InVal))))[2:])[-2:]
			# the [2:] deletes the '0x' prefix. The '0' and [-2:] prepend extra zero if needed
		except ValueError: OutStr += '00' # traps any values in HexTuple not convertible to integers
	return OutStr

ChopFromEnd = lambda InStr,ChopHowMany : (InStr + ' ')[:(-ChopHowMany)-1] # function to remove ChopHowMany chars from end of InStr
	# Simply using InStr[:-ChopHowMany] fails when ChopHowMany = 0

def StripSpaces(instr, CharsToStrip=' '):
	""" Return instr with all spaces (or other characters in CharsToStrip) removed """
	res = ''
	for i in instr:
		if not (i in CharsToStrip): res += i
	return res

_bool_regexp = re.compile(r'''
						  ^\s* #matches whitespace at beginning of string
						  (?:(?P<true>true|yes|[yt]|1)| #matches true values
						  (?P<false>false|no|[fn]|0)) #matches false values
						  \s*$ #matches whitespace at end of string
						  ''', flags=re.IGNORECASE | re.VERBOSE)

def str_to_bool(val):
	"""
	Converts str(val) into a boolean. Raises ValueError if str(val) is not a
	valid string representation of a boolean.

	Valid strings are (case insensitive):

		True  -> 1, true, t, y, yes
		False -> 0, false, f, n, no

	Leading and trailing whitespace will be ignored.
	"""
	# define a regular expression for matching string representations of boolean values
	# this will match any upper or lower case version of y, yes, t, true, 1, n, no,
	# f, false or 0. Leading or trailing whitespace will be ignored.
	match = _bool_regexp.match(str(val))
	if match is not None:
		if match.groupdict()['true'] is None:
			return False
		else:
			return True
	else:
		raise ValueError("Invalid string \'%s\' for conversion to boolean type." % val)

def MergeDicts(*dict_args):
	'''
	Given any number of dicts, shallow copy and merge into a new dict. Return the new dict.
	If any key appears in >1 dict, it will be assigned the value in the rightmost dict.
	'''
	result = {}
	for dictionary in dict_args:
		result.update(dictionary)
	return result

def StringOfIntsToList(Instr, SplitChar=','):
	# return a list of ints converted from string. eg '1,2,  3' --> [1,2,3]
	# Not currently used. Maybe eval() might be better way?
	assert isinstance(Instr, str), "StringOfIntsToList got a non-string Instr"
	assert isinstance(SplitChar, str), "StringOfIntsToList got a non-string SplitChar"
	return [int(x) for x in Instr.split(SplitChar)]

def NextID(ObjList):
	# return the next available ID for a new object getting added to ObjList
	# ObjList: list of any kind of object that has attribute ID (any type convertible to int)
	assert hasattr(ObjList, '__iter__'), "Object list sent to NextID isn't iterable"
	return max([int(e.ID) for e in ObjList] + [0]) + 1 # generate unique ID

def ObjectWithID(Objects, TargetID): # return object instance among Objects (list/set of object instances)
	# with specified ID (str). Returns None if ID not found
	# check Objects is iterable (list, set etc)
	assert hasattr(Objects, '__iter__'), "Object list sent to ObjectWithID isn't iterable"
	for p in Objects:
		# check Objects have ID attributes
		assert hasattr(p, 'ID'), "Object item doesn't have ID attribute"
	ObjIDs = [p.ID for p in Objects]
	if TargetID in ObjIDs:
		return Objects[ObjIDs.index(TargetID.strip())]
	else:
		print("ObjectWithID: warning, requested object ID '%s' not found" % str(TargetID))
		raise
		return None

def FetchObjsFromIDList(IDList, ObjList):
	# extract and return list of objects from ObjList whose ID attrib is in IDList, in order of IDList
	# It is assumed that every object in ObjList has an ID attrib, and that every ID in IDList is included in ObjList
	# IDList can be either a list, or a string containing IDs separated by commas
	assert isinstance(IDList, (list, str))
	assert isinstance(ObjList, list)
	# below, we use replace().split() instead of split(',') to avoid problems if IDList is ''
	IDsToFind = IDList.replace(',', ' ').split() if isinstance(IDList, str) else IDList
	return [ObjectWithID(Objects=ObjList, TargetID=i) for i in IDsToFind]
	# TODO for efficiency, insert code from ObjectWithID() here; don't make list of object IDs every time

def IsEffectivelyZero(TestVal=0.0):
	# returns True if TestVal (int or float) is close to zero, ie unsuitable as a dividend
	assert isinstance(TestVal, (int, float))
	return (abs(TestVal) < ZeroThreshold)

def EffectivelyEqual(Val1, Val2, Precision=0.0001):
	# returns True if Val1 and Val2 (int or float) are equal to within a factor of Precision (float).
	# if Val1 and Val2 are both effectively zero, returns True.
	# Otherwise, if either Val1 or Val2 are effectively zero, returns False.
	assert isinstance(Val1, (int, float))
	assert isinstance(Val2, (int, float))
	assert isinstance(Precision, float)
	if IsEffectivelyZero(Val1):
		if IsEffectivelyZero(Val2): return True
		else: return False
	else:
		if IsEffectivelyZero(Val2): return False
		else:
			return bool( abs((Val1 - Val2)/Val2) < abs(Precision) )

def RoundToSigFigs(InputValue, SigFigs=3):
	# returns ( InputValue (int or float) rounded to SigFigs (int, >0) significant figures,
	#   Number of significant decimal places (int) )
	# From SILability 1.21
	assert type(InputValue) in [int, float]
	assert isinstance(SigFigs, int)
	if IsEffectivelyZero(float(InputValue)):
		return (0.0, 0) # to avoid crash when trying to take log10(0.0)
	else:
		SigFigs = max(1, SigFigs) # ensure SigFigs > 0
		# + 1e-15 is to ensure correct result for InputValue that's an exact power of 10
		Decimals = int(SigFigs - ceil(log10(abs(InputValue)) + 1e-15))
		return (round(InputValue, Decimals), Decimals)

def RoundValueForDisplay(InputValue, SigFigs=3, SciLowerLimit=1e-4, SciUpperLimit=1e6):
	# return InputValue (float or int) as str with specified number of significant figures.
	# if abs(InputValue) <= SciLowerLimit or >= SciUpperLimit, it will be shown in scientific notation.
	assert isinstance(InputValue, (float, int))
	assert isinstance(SigFigs, int)
	assert SigFigs > 0
	assert isinstance(SciLowerLimit, (float, int))
	assert isinstance(SciUpperLimit, (float, int))
	assert 0 < SciLowerLimit < SciUpperLimit
	AbsValue = abs(InputValue)
	# round the value, and find out how many digits to show after the decimal place
	(RoundedValue, SigDecimals) = RoundToSigFigs(AbsValue, SigFigs)
	if SciLowerLimit < AbsValue < SciUpperLimit: # show in non-scientific notation
		# format the display with the correct number of digits before and after the decimal place
		OutStr = '%*.*f' % (SigFigs, SigDecimals, RoundedValue)
	else: # show in scientific notation
		OutStr = '%*.*e' % (SigFigs, SigFigs - 1, RoundedValue)
	# add negative sign if InputValue is negative
	if InputValue < 0: OutStr = '-' + OutStr
	return OutStr

def TextAsString(XMLTag, ValueIfEmpty=''): # return text from XMLTag.
	# If empty (no text in the XML tag), or if text contains whitespace only, return ValueIfEmpty
	# (We use this function because just calling XMLTag.text will return None if text is empty)
	# This procedure is taken from SILability
	T = XMLTag.text
	if T is None: return ValueIfEmpty
	elif not T.strip(): return ValueIfEmpty
	else: return T.strip()

def SortOnValues(InList, ResultField, SortKeyField):
	"""
	InList is a list (or nested lists) of dictionaries
    returns a list of ResultField values, sorted according to the values of
    corresponding SortKeyField entries

	>>> l = [{'a':1, 'b':10},{'a':2, 'b':9}]
	>>> SortOnValues(l, 'b', 'a')
	[10, 9]
	>>> SortOnValues(l, 'a', 'b')
	[2, 1]
	>>> l = [[{'a':1, 'b':10},{'a':2, 'b':9}], [[{'a':3, 'b':8}], {'a':4, 'b':7}]]
	>>> SortOnValues(l, 'b', 'a')
	[10, 9, 8, 7]
	"""
	assert type(InList) == list

	if not InList:
		return []

	# merge nested lists into a single list
	dict_list = Flatten(InList, ltypes=(list))
	# build a list of (key, values), sorted on keys
	result_list = sorted([(d[SortKeyField], d[ResultField]) for d in dict_list], key=lambda x: x[0])
	# return list of values
	return [i[1] for i in result_list]

def Flatten(l, ltypes=(list, tuple)):
	"""
	Reduces any iterable containing other iterables into a single list
	of non-iterable items. The ltypes option allows control over what
	element types will be flattened.
	Returns iterable of the same type as l, containing all member items of l that are of types given in ltypes.
	If l is an empty iterable, returns empty iterable.
	This algorithm is taken from:
	http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html

	>>> print Flatten([range(2),range(3,6)])
	[0, 1, 3, 4, 5]
	>>> print Flatten([1,2,(3,4)])
	[1, 2, 3, 4]
	>>> print Flatten([1,[2,3,[4,5,[6,[7,8,[9,[10]]]]]]])
	[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
	>>> print Flatten([1,[2,3,[4,5,[6,[7,8,[9,[10]]]]]]], ltypes=())
	[1, [2, 3, [4, 5, [6, [7, 8, [9, [10]]]]]]]
	>>> print Flatten([1,2,(3,4)],ltypes=(list))
	[1, 2, (3, 4)]
	"""
	ltype = type(l)
	l = list(l)
	i = 0
	while i < len(l):
		while isinstance(l[i], ltypes):
			if not l[i]:
				l.pop(i)
				i -= 1
				break
			else:
				l[i:i + 1] = l[i]
		i += 1
	return ltype(l)

def SplitList(InList, HowManySublists):
	# split items in InList into a list of lists, containing a total of HowManySublists inner lists
	# e.g. SplitList([1,2,3,4,5,6], 3) returns [[1,2],[3,4],[5,6]]
	assert hasattr(InList, '__iter__')
	assert isinstance(HowManySublists, int)
	assert HowManySublists > 0
	assert len(InList) % HowManySublists == 0 # len(InList) must be exact multiple of HowManySublists
	return [InList[c*len(InList)//HowManySublists:((c+1)*len(InList)//HowManySublists)] for c in range(HowManySublists)]

def SplitListNested(InList, HowManySublistsPerLevel):
	# split items in InList into a nested list of lists, containing HowManySublistsPerLevel[n] sublists at level n
	# e.g. SplitList([1,2,3,4,5,6,7,8,9,10,11,12], [2,3]) returns [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]]
	assert hasattr(InList, '__iter__')
	assert hasattr(HowManySublistsPerLevel, '__iter__')
	if len(HowManySublistsPerLevel) == 1: # this is the last level of depth
		if isinstance(InList[0], list): # if InList already contains lists, split each list
			return [SplitList(InList=InList[i], HowManySublists=HowManySublistsPerLevel[0]) for i in range(len(InList))]
		else: return SplitList(InList=InList, HowManySublists=HowManySublistsPerLevel[0])
	else: # not the last level of depth; split at this level, and iterate for each new list created
		return [SplitListNested(InList=j, HowManySublistsPerLevel=HowManySublistsPerLevel[1:])
			for j in SplitList(InList=InList, HowManySublists=HowManySublistsPerLevel[0])]

def CompareTuple(first, second, element=0):
	"""
	Compares two tuples based on their values at the index given by element.
	Returns int: 1 if element in first > element in second, 0 if equal, -1 if second > first.
	Currently not used. Previously this was the cmp arg in sort() functions.
	>>> print CompareTuple((1,2),(1,3))
	0
	>>> print CompareTuple((1,2),(2,1))
	-1
	>>> print CompareTuple((1,2),(2,1),element=1)
	1
	"""
	ElInFirst = first[element]
	ElInSecond = second[element]
	if ElInFirst > ElInSecond: return 1
	elif ElInFirst < ElInSecond: return -1
	else: return 0

def Bool2Str(Input, TrueStr='y', FalseStr='n'):
	# convert between boolean and string. If Input is bool, Output will be TrueStr or FalseStr.
	# If input is str, output will be bool.
	# Input str's interpreted as True: Y Yes True 1 (case insensitive). Any other str value interpreted as False.
	# Leading and trailing whitespace is ignored.
	assert isinstance(Input, (bool, str))
	if isinstance(Input, bool): return {True: TrueStr, False: FalseStr}[Input]
	else: return Input.strip().upper() in ['Y', 'YES', 'TRUE', '1']

def UnpackPairsList(Instr, IntraPairSeparator='~', InterPairSeparator=','):
	# Instr (str) contains zero or more items 'x~y' (x, y arbitrary strings not containing ~) separated by commas.
	# Returns list of tuples [ (x1, y1), (x2, y2)... ]
	assert isinstance(Instr, str)
	assert isinstance(IntraPairSeparator, str)
	assert isinstance(InterPairSeparator, str)
	if Instr:
		return [tuple(Pair.split(IntraPairSeparator)) for Pair in Instr.split(InterPairSeparator)]
	else: return [] # needed because ''.split('x') returns [''] not [] if split's arg is defined

def TextWithoutSpecialChars(InText):
	# returns string with 'special characters' in InText processed. Currently:
	# smart single/double quotes are converted to straight single/double quotes
	# This is used as a workaround to deal with behaviour of ExpandoTextCtrl, which seems to convert 'quotes' to
	# smart quotes unbidden
	assert isinstance(InText, str)
	ConversionHash = {u'\u2018': "'", u'\u2019': "'", u'\u201c': '"', u'\u201d': '"'}
	# check and process each char in InText
	# convert if the char is in ConversionHash, else keep the same char
	return ''.join([ConversionHash.get(ThisChar, ThisChar) for ThisChar in InText])

def InstanceWithAttribValue(ObjList, AttribName, TargetValue, NotFoundValue=None):
	# find the first object in ObjList (iterable of structured objects) whose attrib with AttribName (str) == TargetValue.
	# return the object.
	# If no object in ObjList has attrib = TargetValue, return NotFoundValue.
	# If all objects in ObjList don't have an attrib with AttribName, return NotFoundValue.
	assert hasattr(ObjList, '__iter__')
	assert isinstance(AttribName, str)
	# choose a suitable 'no such attrib' value. We can't just use None in case TargetValue is None
	NoSuchAttribValue = 'X' if TargetValue is None else None
	AttribValues = [getattr(ThisObj, AttribName, NoSuchAttribValue) for ThisObj in ObjList]
	if TargetValue in AttribValues:
		return ObjList[AttribValues.index(TargetValue)]
	else: return NotFoundValue


import os, sys
import urllib, requests
import psycopg2
from google.cloud import storage
from flask import Flask, request, session, render_template, redirect, url_for
import urllib.parse, urllib.request, json, pickle
import pandas as pd
from postgres import *
app = Flask(__name__)
app.secret_key = "Mahasweta"

def clean():
	dir_name = os.path.join(os.path.dirname(__file__),"static","images")
	test = os.listdir(dir_name)
	for item in test:
	    if item.endswith(".png"):
	        os.remove(os.path.join(dir_name, item))

def download_blob(source_blob_name, destination_file_name, bucket_name = "procvaxx"):
	storage_client = storage.Client.create_anonymous_client()
	bucket_t = storage_client.bucket("procvaxx", user_project=None)
	temp = storage.Blob(source_blob_name, bucket_t)

	temp.download_to_filename(destination_file_name)

data = pd.read_csv('samples.csv')
file_list = []

for ind in data.index:
	file_list.append(data["filename"][ind])

@app.route('/')
def launch():
	return redirect(url_for('initial'))

@app.route('/login')
def initial():
	initiate()
	return render_template('login.html',warning="")

@app.route('/login',methods=['GET','POST'])
def login():
	if request.method == 'POST':
		session['name'] = request.form.get('nm',None).casefold()
		if not session['name']:
			return render_template('login.html',warning="***Please Enter Valid username***")
	try:
		_ = add_column(session["name"])
		return redirect(url_for('update'))
	except Exception as e:
		return redirect(url_for('login'))

# @app.route('/about',methods=['GET','POST'])
# def about():
# 	try:
# 		session["name"]
# 		return render_template('about.html')
# 	except:
# 		return redirect(url_for('initial'))

# @app.route('/proceed',methods=['GET','POST'])
# def proceed():
# 	try:
# 		request.form.get('next')
# 		_ = add_column(session["name"])
# 		return redirect(url_for('update'))
# 	except Exception as e:
# 		print(e)
# 		return redirect(url_for('about'))

@app.route('/input', methods=['GET','POST'])
def update():
	try:
		_ = session["name"]
	except:
		return redirect(url_for('login'))

	if 'action' in request.form:
		while 1 :
			if request.form.get('action') == "Irrelevant":
				save(session["file"],session["name"],"N/A")
				break

			elif request.form.get('action') == "Submit":
				label = request.form.get('label',None)
				misinf = request.form.get('misinf',None)
				# print(label,type(label))
				if label and misinf:
					out = str(label) + str(misinf)
					save(session["file"],session["name"],out)
					break

	clean() #remove images

	(session["count"],top) = start(session["name"])
	#finish
	if session["count"] == 2000:
		return redirect(url_for('finish'))
		#dummy column
	elif not top:
		(session["count"],top) = start(session["name"])

	# print("From main",top)
	(session["file"],caption,image_text) = top[:3]
	image_path = os.path.join("static","images",session["file"].strip("xxx-").replace("json","png"))
	#download image
	download_blob(session["file"].replace(".json",".png"), image_path)

	percent = int((session["count"]/2000)*100)
	args = {"name": session['name'],"count":session["count"],"caption": caption,"image_text":image_text,
	"image": image_path,"percent":percent}
	return render_template('labeling_template.html',**args)

@app.route('/finish')
def finish():
	return render_template('finish.html')

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


import argparse
import gym
import gymfc
import matplotlib.pyplot as plt
import numpy as np
from mpi4py import MPI
import math
import os

"""
This script evaluates a PID controller in the GymFC environment. This can be
used as a baseline for comparing to other control algorihtms in GymFC and also
to confirm the GymFC environment is setup and installed correctly.

The PID and mix settings reflect what was used in the following paper,

Koch, William, Renato Mancuso, Richard West, and Azer Bestavros.
"Reinforcement Learning for UAV Attitude Control." arXiv
preprint arXiv:1804.04154 (2018).

For reference, PID

PID Roll = [2, 10, 0.005]
PID PITCH = [10, 10, 0.005]
PID YAW = [4, 50, 0.0]

and mix for values throttle, roll, pitch, yaw,

rear right motor = [ 1.0, -1.0,  0.598, -1.0 ]
front rear motor = [ 1.0, -0.927, -0.598,  1.0 ]
rear left motor  = [ 1.0,  1.0,  0.598,  1.0 ]
front left motor = [ 1.0,  0.927, -0.598, -1.0 ]

PID terms were found first using the Ziegler–Nichols method and then manually tuned
for increased response. The Iris quadcopter does not have an X frame therefore
a custom mixer is required. Using the mesh files found in the Gazebo models they were
imported into a CAD program and the motor constraints were measured. Using these
values the mix calculater found here, https://www.iforce2d.net/mixercalc, was
used to derive the values. The implmementation of the PID controller can be found here,
https://github.com/ivmech/ivPID/blob/master/PID.py, windup has been removed so
another variable was not introduced.
"""

def plot_step_response(desired, actual,
                 end=1., title=None,
                 step_size=0.001, threshold_percent=0.1):
    """
        Args:
            threshold (float): Percent of the start error
    """

    #actual = actual[:,:end,:]
    end_time = len(desired) * step_size
    t = np.arange(0, end_time, step_size)

    #desired = desired[:end]
    threshold = threshold_percent * desired

    plot_min = -math.radians(350)
    plot_max = math.radians(350)

    subplot_index = 3
    num_subplots = 3

    f, ax = plt.subplots(num_subplots, sharex=True, sharey=False)
    f.set_size_inches(10, 5)
    if title:
        plt.suptitle(title)
    ax[0].set_xlim([0, end_time])
    res_linewidth = 2
    linestyles = ["c", "m", "b", "g"]
    reflinestyle = "k--"
    error_linestyle = "r--"

    # Always
    ax[0].set_ylabel("Roll (rad/s)")
    ax[1].set_ylabel("Pitch (rad/s)")
    ax[2].set_ylabel("Yaw (rad/s)")

    ax[-1].set_xlabel("Time (s)")

    """ ROLL """
    # Highlight the starting x axis
    ax[0].axhline(0, color="#AAAAAA")
    ax[0].plot(t, desired[:,0], reflinestyle)
    ax[0].plot(t, desired[:,0] -  threshold[:,0] , error_linestyle, alpha=0.5)
    ax[0].plot(t, desired[:,0] +  threshold[:,0] , error_linestyle, alpha=0.5)

    r = actual[:,0]
    ax[0].plot(t[:len(r)], r, linewidth=res_linewidth)

    ax[0].grid(True)

    """ PITCH """

    ax[1].axhline(0, color="#AAAAAA")
    ax[1].plot(t, desired[:,1], reflinestyle)
    ax[1].plot(t, desired[:,1] -  threshold[:,1] , error_linestyle, alpha=0.5)
    ax[1].plot(t, desired[:,1] +  threshold[:,1] , error_linestyle, alpha=0.5)
    p = actual[:,1]
    ax[1].plot(t[:len(p)],p, linewidth=res_linewidth)
    ax[1].grid(True)

    """ YAW """
    ax[2].axhline(0, color="#AAAAAA")
    ax[2].plot(t, desired[:,2], reflinestyle)
    ax[2].plot(t, desired[:,2] -  threshold[:,2] , error_linestyle, alpha=0.5)
    ax[2].plot(t, desired[:,2] +  threshold[:,2] , error_linestyle, alpha=0.5)
    y = actual[:,2]
    ax[2].plot(t[:len(y)],y , linewidth=res_linewidth)
    ax[2].grid(True)

    plt.show()

class Policy(object):
    def action(self, state, sim_time=0, desired=np.zeros(3), actual=np.zeros(3) ):
        pass
    def reset(self):
        pass

class PIDPolicy(Policy):
    def __init__(self):
        self.r = [2, 10, 0.005]
        self.p = [10, 10, 0.005]
        self.y = [4, 50, 0.0]
        self.controller = PIDController(pid_roll = self.r, pid_pitch = self.p, pid_yaw =self.y )

    def action(self, state, sim_time=0, desired=np.zeros(3), actual=np.zeros(3) ):
        # Convert to degrees
        desired = list(map(math.degrees, desired))
        actual = list(map(math.degrees, actual))
        motor_values = np.array(self.controller.calculate_motor_values(sim_time, desired, actual))
        # Need to scale from 1000-2000 to -1:1
        return np.array( [ (m - 1000)/500  - 1 for m in motor_values])

    def reset(self):
        self.controller = PIDController(pid_roll = self.r, pid_pitch = self.p, pid_yaw = self.y )

def eval(env, pi):
    actuals = []
    desireds = []
    pi.reset()
    ob = env.reset()
    while True:
        desired = env.omega_target
        actual = env.omega_actual
        # PID only needs to calculate error between desired and actual y_e
        ac = pi.action(ob, env.sim_time, desired, actual)
        ob, reward, done, info = env.step(ac)
        actuals.append(actual)
        desireds.append(desired)
        if done:
            break
    env.close()
    return desireds, actuals

"""
This is essentially a port from Betaflight

For the iris the motors have the following constraints,
https://www.iforce2d.net/mixercalc/
4 2 409
2 1 264
4 3 264
3 1 441
4 1 500
2 3 500

"""

class PIDController(object):
    FD_ROLL = 0
    FD_PITCH = 1
    FD_YAW = 2
    PTERM_SCALE = 0.032029
    ITERM_SCALE = 0.244381
    DTERM_SCALE = 0.000529
    minthrottle = 1070
    maxthrottle = 2000

    def __init__(self, pid_roll = [40, 40, 30], pid_pitch = [58, 50, 35], pid_yaw = [80, 45, 20], itermLimit=150):

        # init gains and scale
        self.Kp = [pid_roll[0], pid_pitch[0], pid_yaw[0]]
        self.Kp = [self.PTERM_SCALE * p for p in self.Kp]

        self.Ki = [pid_roll[1], pid_pitch[1], pid_yaw[1]]
        self.Ki = [self.ITERM_SCALE * i for i in self.Ki]

        self.Kd = [pid_roll[2], pid_pitch[2], pid_yaw[2]]
        self.Kd = [self.DTERM_SCALE * d for d in self.Kd]

        self.itermLimit = itermLimit

        self.previousRateError = [0]*3
        self.previousTime = 0
        self.previous_motor_values = [self.minthrottle]*4
        self.pid_rpy = [PID(*pid_roll), PID(*pid_pitch), PID(*pid_yaw)]

    def calculate_motor_values(self, current_time, sp_rates, gyro_rates):
        rpy_sums = []
        for i in range(3):
            self.pid_rpy[i].SetPoint = sp_rates[i]
            self.pid_rpy[i].update(current_time, gyro_rates[i])
            rpy_sums.append(self.pid_rpy[i].output)
        return self.mix(*rpy_sums)

    def constrainf(self, amt, low, high):
        # From BF src/main/common/maths.h
        if amt < low:
            return low
        elif amt > high:
            return high
        else:
            return amt

    def mix(self, r, p, y):
        PID_MIXER_SCALING = 1000.0
        pidSumLimit = 10000.#500
        pidSumLimitYaw = 100000.#1000.0#400
        motorOutputMixSign = 1
        motorOutputRange = self.maxthrottle - self.minthrottle# throttle max - throttle min
        motorOutputMin = self.minthrottle

        currentMixer=[
            [ 1.0, -1.0,  0.598, -1.0 ],          # REAR_R
            [ 1.0, -0.927, -0.598,  1.0 ],          # RONT_R
            [ 1.0,  1.0,  0.598,  1.0 ],          # REAR_L
            [ 1.0,  0.927, -0.598, -1.0 ],          # RONT_L
        ]
        mixer_index_throttle = 0
        mixer_index_roll = 1
        mixer_index_pitch = 2
        mixer_index_yaw = 3

        scaledAxisPidRoll = self.constrainf(r, -pidSumLimit, pidSumLimit) / PID_MIXER_SCALING
        scaledAxisPidPitch = self.constrainf(p, -pidSumLimit, pidSumLimit) / PID_MIXER_SCALING
        scaledAxisPidYaw = self.constrainf(y, -pidSumLimitYaw, pidSumLimitYaw) / PID_MIXER_SCALING
        scaledAxisPidYaw = -scaledAxisPidYaw

        # Find roll/pitch/yaw desired output
        motor_count = 4
        motorMix = [0]*motor_count
        motorMixMax = 0
        motorMixMin = 0
        # No additional throttle, in air mode
        throttle = 0
        motorRangeMin = 1000
        motorRangeMax = 2000

        for i in range(motor_count):
            mix = (scaledAxisPidRoll  * currentMixer[i][1] +
                scaledAxisPidPitch * currentMixer[i][2] +
                scaledAxisPidYaw   * currentMixer[i][3])

            if mix > motorMixMax:
                motorMixMax = mix
            elif mix < motorMixMin:
                motorMixMin = mix
            motorMix[i] = mix

        motorMixRange = motorMixMax - motorMixMin
        #print("range=", motorMixRange)

        if motorMixRange > 1.0:
            for i in range(motor_count):
                motorMix[i] /= motorMixRange
            # Get the maximum correction by setting offset to center when airmode enabled
            throttle = 0.5

        else:
            # Only automatically adjust throttle when airmode enabled. Airmode logic is always active on high throttle
            throttleLimitOffset = motorMixRange / 2.0
            throttle = self.constrainf(throttle, 0.0 + throttleLimitOffset, 1.0 - throttleLimitOffset)

        motor = []
        for i in range(motor_count):
            motorOutput = motorOutputMin + (motorOutputRange * (motorOutputMixSign * motorMix[i] + throttle * currentMixer[i][mixer_index_throttle]))
            motorOutput = self.constrainf(motorOutput, motorRangeMin, motorRangeMax);
            motor.append(motorOutput)

        motor = list(map(int, np.round(motor)))
        return motor

    def is_airmode_active(self):
        return True

    def reset(self):
        for pid in self.pid_rpy:
            pid.clear()

# This file is part of IvPID.
# Copyright (C) 2015 Ivmech Mechatronics Ltd. <bilgi@ivmech.com>
#
# IvPID is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IvPID is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# title           :PID.py
# description     :python pid controller
# author          :Caner Durmusoglu
# date            :20151218
# version         :0.1
# notes           :
# python_version  :2.7
# ==============================================================================

"""Ivmech PID Controller is simple implementation of a Proportional-Integral-Derivative (PID) Controller in the Python Programming Language.
More information about PID Controller: http://en.wikipedia.org/wiki/PID_controller
"""
import time

class PID:
    """PID Controller
    """

    def __init__(self, P=0.2, I=0.0, D=0.0):

        self.Kp = P
        self.Ki = I
        self.Kd = D

        self.sample_time = 0.00
        self.current_time = 0
        self.last_time = self.current_time

        self.clear()

    def clear(self):
        """Clears PID computations and coefficients"""
        self.SetPoint = 0.0

        self.PTerm = 0.0
        self.ITerm = 0.0
        self.DTerm = 0.0
        self.last_error = 0.0

        # Windup Guard
        self.int_error = 0.0
        self.windup_guard = 20.0

        self.output = 0.0

    def update(self, current_time, feedback_value):
        """Calculates PID value for given reference feedback

        .. math::
            u(t) = K_p e(t) + K_i \int_{0}^{t} e(t)dt + K_d {de}/{dt}

        .. figure:: images/pid_1.png
           :align:   center

           Test PID with Kp=1.2, Ki=1, Kd=0.001 (test_pid.py)

        """
        error = self.SetPoint - feedback_value

        delta_time = current_time - self.last_time
        delta_error = error - self.last_error

        if (delta_time >= self.sample_time):
            self.PTerm = self.Kp * error
            self.ITerm += error * delta_time

            if (self.ITerm < -self.windup_guard):
                self.ITerm = -self.windup_guard
            elif (self.ITerm > self.windup_guard):
                self.ITerm = self.windup_guard

            self.DTerm = 0.0
            if delta_time > 0:
                self.DTerm = delta_error / delta_time

            # Remember last time and last error for next calculation
            self.last_time =current_time
            self.last_error = error

            #print("P=", self.PTerm, " I=", self.ITerm, " D=", self.DTerm)
            self.output = self.PTerm + (self.Ki * self.ITerm) + (self.Kd * self.DTerm)

    def setKp(self, proportional_gain):
        """Determines how aggressively the PID reacts to the current error with setting Proportional Gain"""
        self.Kp = proportional_gain

    def setKi(self, integral_gain):
        """Determines how aggressively the PID reacts to the current error with setting Integral Gain"""
        self.Ki = integral_gain

    def setKd(self, derivative_gain):
        """Determines how aggressively the PID reacts to the current error with setting Derivative Gain"""
        self.Kd = derivative_gain

    def setWindup(self, windup):
        """Integral windup, also known as integrator windup or reset windup,
        refers to the situation in a PID feedback controller where
        a large change in setpoint occurs (say a positive change)
        and the integral terms accumulates a significant error
        during the rise (windup), thus overshooting and continuing
        to increase as this accumulated error is unwound
        (offset by errors in the other direction).
        The specific problem is the excess overshooting.
        """
        self.windup_guard = windup

    def setSampleTime(self, sample_time):
        """PID that should be updated at a regular interval.
        Based on a pre-determined sampe time, the PID decides if it should compute or return immediately.
        """
        self.sample_time = sample_time

def main(env_id, seed):
    env = gym.make(env_id)
    rank = MPI.COMM_WORLD.Get_rank()
    workerseed = seed + 1000000 * rank
    env.seed(workerseed)
    pi = PIDPolicy()
    desireds, actuals = eval(env, pi)
    title = "PID Step Response in Environment {}".format(env_id)
    plot_step_response(np.array(desireds), np.array(actuals), title=title)

if __name__ == "__main__":

    parser = argparse.ArgumentParser("Evaluate a PID controller")
    parser.add_argument('--env-id', help="The Gym environement ID", type=str,
                        default="AttFC_GyroErr-MotorVel_M4_Ep-v0")
    parser.add_argument('--seed', help='RNG seed', type=int, default=17)

    args = parser.parse_args()
    current_dir = os.path.dirname(__file__)
    config_path = os.path.join(current_dir,
                               "../configs/iris.config")
    print ("Loading config from ", config_path)
    os.environ["GYMFC_CONFIG"] = config_path

    main(args.env_id, args.seed)


from django.shortcuts import render, redirect
import datetime, unicodedata, webbrowser, time
from alarm.models import Alarm

###################################################################################
def check_alarm_time(alarm_time):
	# Consider alarm_time is a string(strftime)
	now = datetime.datetime.now().strftime("%H:%M")
	if not alarm_time >= now:
		return False
	return True

def check_and_render(request, alarm_time, s_dict, errors):
	if not check_alarm_time(alarm_time):
		error = "Please Enter a future time"
		errors.append(error)
		s_dict["errors"] = error
		return s_dict

def uni_to_str(uni):
	return unicodedata.normalize('NFKD', uni).encode('ascii','ignore')

def get_alarm_time_from_duration(duration):
	try:
		alarm_hours = int(duration[:2])
		alarm_minutes = int(duration[3:])
	except:
		alarm_hours = 0
		alarm_minutes = 0
	return (alarm_hours, alarm_minutes)

def get_client_ip(request):
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        ip = x_forwarded_for.split(',')[0]
    else:
        ip = request.META.get('REMOTE_ADDR')
    return ip

def check_and_save(request, alarm_time):
	ip = get_client_ip(request)
	current_alarm = None
	for alarm in Alarm.objects.all():
		if ip == alarm.ip_address:
			current_alarm = alarm
			break

	if current_alarm == None:
		current_alarm = Alarm(alarm_time=alarm_time, ip_address=ip)
	else:
		current_alarm.alarm_time = alarm_time

	current_alarm.save()

#####################################################################################

def alarm(request):
	"""
	Validate the input given by the user, report the errors and if no errors found  add it to the database.
	"""
	errors = []
	if "alarm_time" in request.POST and request.POST.get("alarm_time", None) != "":
		# Extract the information about the alarm_time
		alarm_time_u = request.POST.get("alarm_time", "Not Set")

		# Convert from unicode to python string
		alarm_time = uni_to_str(alarm_time_u)

		# Make datetime objects.
		try:
			alarm_time = datetime.datetime.strptime(alarm_time, "%H:%M")
		except ValueError:
			errors.append("Please enter valid time.")
			return render(request, "index.html", {'errors' : errors})

		now = datetime.datetime.now()

		# Write it to database
		check_and_save(request, alarm_time)

		# Convert them from datetime objects to python strings
		now = datetime.datetime.now().strftime("%H:%M")
		alarm_time = alarm_time.strftime("%H:%M")

		# Preparing HTML variables.
		s_dict = {"alarm_time" : alarm_time, 'now' : now}
		s_dict = check_and_render(request, alarm_time, s_dict, errors)

		if not errors:
			return redirect('/success')

	elif "alarm_duration" in request.POST:
		# Extract the information about the alarm_time
		duration_u = request.POST.get("alarm_duration", "Not Set")

		# Convert from unicode to python string
		duration = uni_to_str(duration_u)
		(alarm_hours, alarm_minutes) = get_alarm_time_from_duration(duration)

		# Create datetime objects
		now = datetime.datetime.now()
		alarm_time = now + datetime.timedelta(hours = alarm_hours, minutes = alarm_minutes)

		# Save the ip and time in database
		check_and_save(request, alarm_time)

		# Convert the time objects to string formats.
		now = now.strftime("%H:%M")
		alarm_time = alarm_time.strftime("%H:%M")

		# Prepare HTML variables.
		s_dict = {"alarm_time" : alarm_time, 'now' : now}
		s_dict = check_and_render(request, alarm_time, s_dict, errors)

		if not errors:
			return redirect('/success')

	# If no request.
	if request.POST.get("alarm_time", None) == "":
		errors.append("Please enter valid Time")
	return render(request, "index.html", {"now": datetime.datetime.now(), 'errors': errors,})

def create_alarm(request):
	ip = get_client_ip(request)
	alarm_time = datetime.datetime.now()
	for alarm in Alarm.objects.all():
		if ip == alarm.ip_address:
			alarm_time = alarm.alarm_time
			break

	alarm_time = alarm_time.strftime("%H:%M:%S")
	now = datetime.datetime.now().strftime("%H:%M")
	s_dict = {"alarm_time" : alarm_time, 'now' : now}
	return render(request, "success.html", s_dict)


class BinarySearchTreeNode:
    def __init__(self, key):
        self.key = key
        self.left = None
        self.right = None
        return

    def insert(self, key):
        if key < self.key:
            if self.left is None:
                self.left = BinarySearchTreeNode(key)
            else:
                self.left.insert(key)
        else:
            if self.right is None:
                self.right = BinarySearchTreeNode(key)
            else:
                self.right.insert(key)

    def is_leaf(self):
        return (self.left is None) and (self.right is None)

    def parenthesis_representation(self):
        if self.is_leaf():
            return '%s' % str(self.key)
        if self.left is None:
            return '%s(- %s)' % (str(self.key), self.right.parenthesis_representation())
        if self.right is None:
            return '%s(%s -)' % (str(self.key), self.left.parenthesis_representation())
        if not self.left.is_leaf():
            return '%s(%s%s)' % (str(self.key), self.left.parenthesis_representation(), self.right.parenthesis_representation())
        return '%s(%s %s)' % (str(self.key), self.left.parenthesis_representation(), self.right.parenthesis_representation())

def parenthesis_representation(input_file, output_file):
    lines = None
    outputs = []
    with open(input_file, mode='r') as f:
        lines = f.readlines()
        f.close()
    for line in lines:
        root = None
        for i, n in enumerate(line.split()):
            n = int(n)
            if i == 0:
                root = BinarySearchTreeNode(n)
            else:
                root.insert(n)
        outputs.append(root.parenthesis_representation()+'\n')
    with open(output_file, mode='w') as f:
        f.writelines(outputs)
        f.close()
    return outputs

def left_boundary(input_file, output_file):
    def dfs(node, current_depth, boundary):
        if node is None:
            return
        if len(boundary) == current_depth:
            boundary.append(str(node.key))
        dfs(node.left, current_depth+1, boundary)
        dfs(node.right, current_depth+1, boundary)
        return
    lines = None
    outputs = []
    with open(input_file, mode='r') as f:
        lines = f.readlines()
        f.close()
    for line in lines:
        root = None
        for i, n in enumerate(line.split()):
            n = int(n)
            if i == 0:
                root = BinarySearchTreeNode(n)
            else:
                root.insert(n)

        boundary = []
        dfs(root, 0, boundary)
        outputs.append(' '.join(boundary)+'\n')
    with open(output_file, mode='w') as f:
        f.writelines(outputs)
        f.close()
    return outputs

def textual_printing(input_file, output_file):
    def inorder(node, current_depth, order):
        if node is None:
            return
        inorder(node.left, current_depth+1, order)
        order.append((node.key, current_depth))
        inorder(node.right, current_depth+1, order)
        return

    lines = None
    outputs = []
    with open(input_file, mode='r') as f:
        lines = f.readlines()
        f.close()
    for line in lines:
        root = None
        for i, n in enumerate(line.split()):
            n = int(n)
            if i == 0:
                root = BinarySearchTreeNode(n)
            else:
                root.insert(n)

        order = []
        inorder(root, 0, order)
        n_row = max(order, key=lambda x: x[1])[1]+1
        n_col = len(order)
        grid = [['  ' for x in range(n_col)] for y in range(n_row)]
        for x, (key, y) in enumerate(order):
            grid[y][x] = str(key)
        print(grid)
        outputs.append(''.join([''.join(line)+'\n' for line in grid])+'\n')
    with open(output_file, mode='w') as f:
        f.writelines(outputs)
        f.close()
    return outputs
        # outputs.append(' '.join(order)+'\n')

def main(input_file):
    parenthesis_representation(input_file, './parenthesis_representation.txt')
    left_boundary(input_file, './left_boundary.txt')
    textual_printing(input_file, 'textual_printing.txt')
    return

if __name__ == '__main__':
    import sys
    main(sys.argv[1])

# class BinarySearchTree:
#     def __init__(self):
#         self.root = None
#         return

#     def is_empty(self):
#         return self.root is None

#     def insert(self, key):
#         if self.is_empty():
#             self.root = BinarySearchTreeNode(key)
#         else:
#             self.root.insert(key)
#         return

#     def inorder_traversal_with_depth(self):

#     def print(self):
#         return


import logging
import string
import ephem
from _datetime import datetime
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackQueryHandler
import os

is_get_answer = False
logging.basicConfig(format='%(name)s - %(levelname)s - %(message)s',
                    level=logging.INFO,
                    filename='bot.log'
                    )

def delete_punctuation(word):
    for char in string.punctuation:
        return word.replace(char, '')

def get_word_count(bot, update):
    raw_sentence = update.message.text.split()
    raw_sentence_to_count = raw_sentence[1:]
    words_amount = 0

    if raw_sentence_to_count[0][0] != '"' and raw_sentence_to_count[-1][-1] != '"':
        update.message.reply_text('Неправильно введена команда, для подсчета слов введите /word_count "предложение"')
        return

    for word in raw_sentence_to_count:
        word = delete_punctuation(word)
        if word:
            words_amount += 1

    update.message.reply_text('Количество слов в предложении = {}'.format(words_amount))

def get_answer(bot, update):
    global is_get_answer
    question = update.message.text
    formated_question = str(question).lower().replace('?', '').strip()
    if formated_question == 'привет':
        update.message.reply_text('Привет {}, '
                                  'ты можешь задать мне пару вопросов и я попробую тебе на них ответить'
                                  .format(update.message.from_user.first_name))

        is_get_answer = True
    elif formated_question == 'пока' and is_get_answer:
        update.message.reply_text('До встречи, рад был пообщаться!')
        is_get_answer = False
    elif is_get_answer:
        answers = {'какая погода': 'сегодня прохладно', 'как дела': 'Лучше всех',
                   'что будет завтра': 'Завтра будет лучше чем вчера'}
        if formated_question in answers:
            update.message.reply_text(answers[formated_question])
        else:
            update.message.reply_text('Я не знаю что тебе на это ответить, попробуй задать другой вопрос')

def greet_user(bot, update):
    text = ('Привет {}'.format(update.message.from_user.first_name))
    update.message.reply_text(text)

def get_planet_constellation(bot, update, args):
    planet_name = args[0]
    print(planet_name)
    try:
        planet = getattr(ephem, planet_name)
    except AttributeError:
        planet = None

    if planet:
        reply = ephem.constellation(planet(datetime.now()))
    else:
        reply = 'Такой планеты нету'

    update.message.reply_text(reply)

def main():
    api_key = os.getenv('TELEGRAM_API_KEY')
    updater = Updater(api_key)

    dp = updater.dispatcher
    dp.add_handler(CommandHandler("start", greet_user))
    dp.add_handler(CommandHandler("get_planet_constellation", get_planet_constellation, pass_args=True))
    dp.add_handler(MessageHandler(Filters.text, get_answer))
    dp.add_handler(CommandHandler("word_count", get_word_count))

    updater.start_polling()
    updater.idle()

if __name__ == '__main__':
    main()


from prettytable import PrettyTable

class PrettyTableWrapper:
    def __init__(
            self, field_names=None,
            sortby=None, reverse_sort=False,
            aligns=None, common_formatter=None
    ):
        """Create PrettyTableWrapper.
        Args:
            field_names (list).
            sortby (str or int) opt: Sorts table by column.
            reverse_sort (bool) opt.
            aligns (iterable) opt: Align setting applied positionally on columns.
                If last align is uppercase, then remaining columns will be aligned that way.
            common_formatter (tuple(idxs_sequence, function)) opt:
                Add common formatter function to selected columns.
        """
        table = PrettyTable(field_names)
        self.table = table
        self.n_columns = len(field_names)
        self.raw_data = []
        self.print_ptr = 0
        self.sortby = sortby
        self.reverse_sort = reverse_sort
        self.format_factories = {}

        if sortby is not None:
            self._apply_sort(sortby, reverse_sort)

        if aligns and len(aligns) != 0:
            if aligns[-1].isupper():
                table.align = aligns[-1].lower()
            for align, field in zip(aligns[:-1], table.field_names):
                table.align[field] = align

        if common_formatter:
            self.update_format_factories({
                idx:common_formatter[1]
                for idx in common_formatter[0]
            })

    def coalesce(self, row_data):
        """Coalesce missing fields with empty string.
        Args:
            row_data (list): Fields data for one ROW.
        """
        # pylint: disable=unused-variable
        for i in range(self.n_columns - len(row_data)):
            row_data.append('')
        return row_data

    def add_coalesce(self, row_data):
        """Adds ROW_data straight to PrettyTable.
        Great if you don't want to mess with raw data.
        Args:
            row_data (list): Fields data for one ROW.
        """
        self.table.add_row(self.coalesce(row_data))

    def update_format_factories(self, factories):
        """Add format functions for row_data.
        Args:
            factories (dict): {column id: function}
        """
        for key in factories:
            if isinstance(key, str):
                factories[self.table.field_names.index(key)] = factories.pop(key)
        self.format_factories.update(factories)

    def write_raw(self, row_data):
        """Appends ROW data to raw_data list. This is saved in wrapper
        and is not added to the PrettyTable until self.add_raw_to_table() is called.
        Args:
            row_data (list): Fields data for one ROW.
        """
        self.raw_data.append(self.coalesce(row_data))

    def add_raw_to_table(self):
        """Adds all yet not printed data from raw_data to PrettyTable.
        Raw_data stays in wrapper and is accessible as list.
        Every call to this method adds only data that hasn't been added yet with this method.
        """
        for row in self.raw_data[self.print_ptr:]:
            self.table.add_row([
                self.format_factories[idx](cell)
                if idx in self.format_factories and
                not cell == '' else cell
                for idx, cell in enumerate(row)
            ])
        self.print_ptr = len(self.raw_data)

    def _apply_sort(self, sortby, reverse_sort):
        self.table.sortby = sortby if isinstance(sortby, str) else self.table.field_names[sortby]
        self.sortby = self.table.field_names.index(self.table.sortby)
        self.reverse_sort = reverse_sort
        self.table.reversesort = self.reverse_sort

    def sort_raw(self):
        """Sorts raw_data based on self.sortby and self.reverse_sort.
        Doesn't sort PrettyTable itself.
        """
        self.raw_data.sort(key=lambda item: item[self.sortby], reverse=self.reverse_sort)

    def re_sort(self, sortby, reverse_sort=False):
        """Resorts raw_data as well as PrettyTable itself.
        Args:
            sortby (int | str): Names of column to sort by or its index in self.table.field_names.
            reverse_sort (bool) opt: False = sort ascending, True = sort descending.
        """
        self._apply_sort(sortby, reverse_sort)
        self.sort_raw()


import os

def extract_char_name(chrct_sentnc, all_name_sent, name_pred):
    chrct_ls = []
    with open(chrct_sentnc, "r") as inf:
        for l in inf:
            chrct_ls.append(l)

    name_sent_dic = {}
    with open(all_name_sent, "r") as inf:
        for l in inf:
            name, sentence = l.split(" ", 1)
            name_sent_dic[sentence] = name

    # character_names
    chrct_name_ls = []
    for s in chrct_ls:
        if s in name_sent_dic.keys():
            chrct_name_ls.append(name_sent_dic[s])
    with open("chrct_name.txt", "w") as ouf:
        for i in sorted(chrct_name_ls):
            ouf.write(i+"\n")

    # character names_

    # character_name pred
    name_pred_dic = {}
    with open(name_pred, "r") as inf:
        for l in inf:
            name, pred = l.split(" ")
            name_pred_dic[name] = pred
    chrct_name_pred = []
    for c_n in chrct_name_ls:
        if c_n in name_pred_dic.keys():
            chrct_name_pred.append(c_n + " " + name_pred_dic[c_n])
    with open("chrct_name_pred.csv", "w") as ouf:
        for c_n_p in sorted(chrct_name_pred):
            ouf.write(c_n_p)

    # copy character wav to dir
    chcter_dir = "jane_eyer_character_dir"
    source_dir = "/home/Data/blizzard2013_part/wav1/jane_eyre"
    if os.path.isdir(chcter_dir):
        os.system("rm -rf {}".format(chcter_dir))
    else:
        os.system("mkdir {}".format(chcter_dir))
    for a in chrct_name_ls:
        chcter_audio = os.path.join(source_dir, a+".wav")
        os.system("cp {} {}".format(chcter_audio, chcter_dir))

if __name__ == '__main__':
    chrct_sentenc = "/home/rosen/Project/ser_model/blizzard13_for_eval/char_sentence.txt"
    all_name_sent = "/home/rosen/Project/ser_model/blizzard13_for_eval/outfile.txt"
    name_pred = "/home/rosen/Project/ser_model/blizzard13_for_eval/emo_feats_elbs.csv"
    extract_char_name(chrct_sentenc, all_name_sent, name_pred)


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('djangobmf_project', '0006_version_0_2_0'),
    ]

    operations = [
        migrations.AlterModelOptions(
            name='project',
            options={'verbose_name': 'Project', 'verbose_name_plural': 'Projects', 'ordering': ['name'], 'permissions': (('can_manage', 'Can manage all projects'),)},
        ),
        migrations.RemoveField(
            model_name='project',
            name='uuid',
        ),
    ]


'''
let n be the number for which to find the square root
let g be the initial guess
let t be the tolerance
let g' be our previous guess, initialized to 0
while the absolute difference between g and g' is greater than t
  g' = g
  g = average of n/g and g
'''

# Don't change these lines
number = int(input("Find the square root of integer: "))
guess = int(input("Initial guess: "))
tolerance = float(input("What tolerance: "))

# Implement the Babylonian square root algorithm

count = 0
prev_guess = 0
while(abs(prev_guess - guess) > tolerance):
    prev_guess = guess
    guess = (number / guess + guess)/2
    count += 1
# Don't change these lines
print("Square root of", number, "is", round(guess, 4))
print("Took", count, "reps to get it to tolerance")


import tamil

with open("result/pos.txt", "r", encoding="utf-8") as file:
    words = [line.rstrip('\n') for line in file]
print('Count of the total Words found: ', len(words))

unique_words = {}
ini = ["ா", "ி", "ீ", "ு", "ூ", "ெ", "ே", "ை", "ொ", "ோ", "்", "ௌ", "ஹ்", "க்", "ங்", "ச்",
       "ஞ்", "ட்", "ண்", "த்", "ந்", "ப்", "ம்", "ய்", "ர்", "ல்", "வ்", "ழ்", "ள்", "ற்", "ன்", "ங", "ற"]

for word in words:
    l = tamil.utf8.get_letters(word.split("-")[0])[0]
    if(not any([l == x for x in ini]) and
       len(tamil.utf8.get_letters(word.split("-")[0]))) > 1:
        unique_words[word] = 1 + unique_words.get(word, 0)

print('Count of the unique Words found: ', len(unique_words))

word_array = {k: v for k, v in sorted(unique_words.items(
), reverse=True, key=lambda item: len(tamil.utf8.get_letters(item[0].split("-")[0])))}

with open("result/result.txt", "w", encoding="utf-8") as f:
    for s in word_array.items():
        f.write(str(s[0].split("-")[0]) + "-" +
                str(len(tamil.utf8.get_letters(s[0].split("-")[0])))+"-"+str(s[1]) + "\n")

word_array = {k: v for k, v in sorted(unique_words.items())}

with open("result/alphabetical.txt", "w", encoding="utf-8") as f:
    for s in word_array.items():
        f.write(str(s[0]) + "-" +
                str(len(tamil.utf8.get_letters(s[0].split("-")[0])))+"-"+str(s[1]) + "\n")


# coding: utf-8

from __future__ import absolute_import
from datetime import date, datetime  # noqa: F401

from typing import List, Dict  # noqa: F401

from swagger_server.models.base_model_ import Model
from swagger_server.models.extended_dispute_resolution import ExtendedDisputeResolution  # noqa: F401,E501
from swagger_server.models.object import Object  # noqa: F401,E501
from swagger_server import util

class ExtendedDispute(Model):
    """NOTE: This class is auto generated by the swagger code generator program.

    Do not edit the class manually.
    """
    def __init__(self, id: str=None, status: str=None, payer_participant: Object=None, disputed_participant: Object=None, creation_time: datetime=None, last_modified: datetime=None, resolution: ExtendedDisputeResolution=None):  # noqa: E501
        """ExtendedDispute - a model defined in Swagger

        :param id: The id of this ExtendedDispute.  # noqa: E501
        :type id: str
        :param status: The status of this ExtendedDispute.  # noqa: E501
        :type status: str
        :param payer_participant: The payer_participant of this ExtendedDispute.  # noqa: E501
        :type payer_participant: Object
        :param disputed_participant: The disputed_participant of this ExtendedDispute.  # noqa: E501
        :type disputed_participant: Object
        :param creation_time: The creation_time of this ExtendedDispute.  # noqa: E501
        :type creation_time: datetime
        :param last_modified: The last_modified of this ExtendedDispute.  # noqa: E501
        :type last_modified: datetime
        :param resolution: The resolution of this ExtendedDispute.  # noqa: E501
        :type resolution: ExtendedDisputeResolution
        """
        self.swagger_types = {
            'id': str,
            'status': str,
            'payer_participant': Object,
            'disputed_participant': Object,
            'creation_time': datetime,
            'last_modified': datetime,
            'resolution': ExtendedDisputeResolution
        }

        self.attribute_map = {
            'id': 'Id',
            'status': 'Status',
            'payer_participant': 'PayerParticipant',
            'disputed_participant': 'DisputedParticipant',
            'creation_time': 'CreationTime',
            'last_modified': 'LastModified',
            'resolution': 'Resolution'
        }
        self._id = id
        self._status = status
        self._payer_participant = payer_participant
        self._disputed_participant = disputed_participant
        self._creation_time = creation_time
        self._last_modified = last_modified
        self._resolution = resolution

    @classmethod
    def from_dict(cls, dikt) -> 'ExtendedDispute':
        """Returns the dict as a model

        :param dikt: A dict.
        :type: dict
        :return: The ExtendedDispute of this ExtendedDispute.  # noqa: E501
        :rtype: ExtendedDispute
        """
        return util.deserialize_model(dikt, cls)

    @property
    def id(self) -> str:
        """Gets the id of this ExtendedDispute.

        :return: The id of this ExtendedDispute.
        :rtype: str
        """
        return self._id

    @id.setter
    def id(self, id: str):
        """Sets the id of this ExtendedDispute.

        :param id: The id of this ExtendedDispute.
        :type id: str
        """
        if id is None:
            raise ValueError("Invalid value for `id`, must not be `None`")  # noqa: E501

        self._id = id

    @property
    def status(self) -> str:
        """Gets the status of this ExtendedDispute.

        :return: The status of this ExtendedDispute.
        :rtype: str
        """
        return self._status

    @status.setter
    def status(self, status: str):
        """Sets the status of this ExtendedDispute.

        :param status: The status of this ExtendedDispute.
        :type status: str
        """
        allowed_values = ["OPEN", "ACKNOWLEDGED", "CLOSED", "CANCELLED"]  # noqa: E501
        if status not in allowed_values:
            raise ValueError(
                "Invalid value for `status` ({0}), must be one of {1}"
                .format(status, allowed_values)
            )

        self._status = status

    @property
    def payer_participant(self) -> Object:
        """Gets the payer_participant of this ExtendedDispute.

        :return: The payer_participant of this ExtendedDispute.
        :rtype: Object
        """
        return self._payer_participant

    @payer_participant.setter
    def payer_participant(self, payer_participant: Object):
        """Sets the payer_participant of this ExtendedDispute.

        :param payer_participant: The payer_participant of this ExtendedDispute.
        :type payer_participant: Object
        """
        if payer_participant is None:
            raise ValueError("Invalid value for `payer_participant`, must not be `None`")  # noqa: E501

        self._payer_participant = payer_participant

    @property
    def disputed_participant(self) -> Object:
        """Gets the disputed_participant of this ExtendedDispute.

        :return: The disputed_participant of this ExtendedDispute.
        :rtype: Object
        """
        return self._disputed_participant

    @disputed_participant.setter
    def disputed_participant(self, disputed_participant: Object):
        """Sets the disputed_participant of this ExtendedDispute.

        :param disputed_participant: The disputed_participant of this ExtendedDispute.
        :type disputed_participant: Object
        """
        if disputed_participant is None:
            raise ValueError("Invalid value for `disputed_participant`, must not be `None`")  # noqa: E501

        self._disputed_participant = disputed_participant

    @property
    def creation_time(self) -> datetime:
        """Gets the creation_time of this ExtendedDispute.

        Data-hora da criação da disputa  # noqa: E501

        :return: The creation_time of this ExtendedDispute.
        :rtype: datetime
        """
        return self._creation_time

    @creation_time.setter
    def creation_time(self, creation_time: datetime):
        """Sets the creation_time of this ExtendedDispute.

        Data-hora da criação da disputa  # noqa: E501

        :param creation_time: The creation_time of this ExtendedDispute.
        :type creation_time: datetime
        """
        if creation_time is None:
            raise ValueError("Invalid value for `creation_time`, must not be `None`")  # noqa: E501

        self._creation_time = creation_time

    @property
    def last_modified(self) -> datetime:
        """Gets the last_modified of this ExtendedDispute.

        Data-hora da última atualização de status  # noqa: E501

        :return: The last_modified of this ExtendedDispute.
        :rtype: datetime
        """
        return self._last_modified

    @last_modified.setter
    def last_modified(self, last_modified: datetime):
        """Sets the last_modified of this ExtendedDispute.

        Data-hora da última atualização de status  # noqa: E501

        :param last_modified: The last_modified of this ExtendedDispute.
        :type last_modified: datetime
        """
        if last_modified is None:
            raise ValueError("Invalid value for `last_modified`, must not be `None`")  # noqa: E501

        self._last_modified = last_modified

    @property
    def resolution(self) -> ExtendedDisputeResolution:
        """Gets the resolution of this ExtendedDispute.

        :return: The resolution of this ExtendedDispute.
        :rtype: ExtendedDisputeResolution
        """
        return self._resolution

    @resolution.setter
    def resolution(self, resolution: ExtendedDisputeResolution):
        """Sets the resolution of this ExtendedDispute.

        :param resolution: The resolution of this ExtendedDispute.
        :type resolution: ExtendedDisputeResolution
        """

        self._resolution = resolution


import importlib.util
from glob import glob
import sys
from colored import fg, stylize
import numpy as np
from utils.Models import *

class ReportGenerator(object):
    def __init__(self, base, mode):
        self.base = base
        self.mode = mode
        self.csv = open(base + "/results.csv", "w")

    def run(self):
        print(stylize("loading load_data.py...", fg("blue")))
        self.load_lib()

        print(stylize("loading goldens...", fg("blue")))
        self.load_goldens()

        if self.mode == "fthls":
            self.run_fthls()
        elif self.mode == "dft":
            self.run_dft()

    def run_fthls(self):
        self.csv.write("address;text;count1;count2;count3;count4;count5;mses")
        vec = TestVector.get(TestVector.code == 1)

        for instr in Instruction.select().where(Instruction.testVec == vec):
            print("Now parsing {}".format(instr.text))
            self.csv.write("\n{};{};".format(instr.address, instr.text))
            for prof in Instruction.select().where(Instruction.address == instr.address).order_by(Instruction.testVec.asc()):
                self.csv.write("{};".format(prof.iters))

            for v in range(1, 6):
                crashang = 30
                for f in glob("{}/outputs/{}-{}-*.out".format(self.base, instr.address, v)):
                    crashang -= 1
                    data = self.lib.load_output(f)
                    if len(data) != len(self.goldens[v-1]):
                        data = np.zeros(len(self.goldens[v-1]))

                    mse = self.calc_mse(data, self.goldens[v-1])
                    self.csv.write("{:.5f};".format(mse))
                for c in range(crashang):
                    self.csv.write("-1;")

        self.csv.close()

    def run_dft(self):
        for v in range(1, 6):
            print("Analyzing vector ", v)
            mses = []
            self.csv.write("vector{};".format(v))
            crashang = 9581
            for f in glob("{}/outputs/*-{}-*.out".format(self.base, v)):
                crashang -= 1
                data = self.lib.load_output(f)
                if len(data) != len(self.goldens[v-1]):
                    data = np.zeros(len(self.goldens[v-1]))

                mse = self.calc_mse(data, self.goldens[v-1])
                mses.append(mse)
                self.csv.write("{:.5f};".format(mse))
            for c in range(crashang):
                self.csv.write("-1;")
            print("Mean MSE:", np.mean(mses))
            print("Max MSE:", max(mses))
            self.csv.write("\n")

        self.csv.close()

    def calc_mse(self, data, golden):
        return np.square(np.subtract(data, golden)).mean()

    def load_goldens(self):
        self.goldens = [self.lib.load_output("{}/outputs/golden-{}-0x0-0.out".format(self.base, v))
                for v in range(1, 6)]

    def load_lib(self):
        spec = importlib.util.spec_from_file_location("TmpLib", "{}/load_data.py".format(self.base))
        module = importlib.util.module_from_spec(spec)
        sys.modules["TmpLib"] = module
        spec.loader.exec_module(module)
        self.lib = module


from pymoab import topo_util
from pymoab import types

class Preprocessor(object):
    """ Preprocessor that computes adjacencies and store them as tags.
    """
    def __init__(self, configs):
        self.configs = configs
        self.adj_config = configs['AdjConfig']
        self.adjacencies = self.adj_config['adjacencies']

    def run(self, moab):
        self._compute_adjacencies(moab)

    def _compute_adjacencies(self, moab):
        """Computes adjacencies and stores them as tags.

        Parameters
        ----------
        moab: MOAB mesh object
            Mesh used to compute the adjacencies. The get_bridge_adjacencies
            method from the topo_util module is used to compute the
            adjacencies.
        """
        mesh_topo_util = topo_util.MeshTopoUtil(moab)
        root_set = moab.get_root_set()

        all_verts = moab.get_entities_by_dimension(root_set, 0)
        mesh_topo_util.construct_aentities(all_verts)

        for (from_dim, bridge_dim, to_dim, layers) in self.adjacencies:
            ents = moab.get_entities_by_dimension(root_set, from_dim)

            adj_tag_name = "__adj_tag_{0}{1}{2}{3}".format(
                from_dim, bridge_dim, to_dim, layers)

            adj_tag = moab.tag_get_handle(
                adj_tag_name, 1, types.MB_TYPE_HANDLE,
                types.MB_TAG_SPARSE, True)

            for ent in ents:
                adjs_meshset = moab.create_meshset()
                adjs = mesh_topo_util.get_bridge_adjacencies(
                    ent, bridge_dim, to_dim, layers)

                moab.add_entities(adjs_meshset, adjs)

                moab.tag_set_data(adj_tag, ent, adjs_meshset)

    @property
    def adj_config(self):
        return self._adj_config

    @adj_config.setter
    def adj_config(self, config):
        if not config:
            raise ValueError("Must have an [AdjConfig] section in the config "
                             "file.")

        self._adj_config = config

    @property
    def adjacencies(self):
        return self._adjacencies

    @adjacencies.setter
    def adjacencies(self, adj_list):
        if not adj_list:
            raise ValueError("Must have a adjacencies option "
                             "under the [AdjConfig] section in the config "
                             "file.")

        adj_list = [tuple(int(val) for val in adj.split('_'))
                    for adj in adj_list]

        self._adjacencies = adj_list


### Python JSON GUI Jokebot Assessment for CSP5110 @ ECU

# Import the required modules.
import tkinter
import tkinter.messagebox
import json

class ProgramGUI:
    def __init__(self):
        self.main = tkinter.Tk()
        try:
            d = open('data.txt', 'r')
            self.data = json.load(d)
            d.close()
        except:
            tkinter.messagebox.showinfo("Error", "Missing or Invalid file. Exiting.")
            exit()
        self.currentJoke = 0

        self.welcome = tkinter.Label(self.main, text="Welcome to JokeBot!", pady=0, fg="Red", font=("Comic Sans MS",30))
        self.welcome.pack()

        self.showJoke()
        self.rateJoke()

    def showJoke(self):
        self.setupVar = tkinter.StringVar()
        self.setupVar.set(self.data[self.currentJoke]["setup"])
        self.punchlineVar = tkinter.StringVar()
        self.punchlineVar.set(self.data[self.currentJoke]["punchline"])
        self.setup = tkinter.Label(self.main, textvariable=self.setupVar, fg="Black", font=("Arial",16,"bold"), wraplengt=500)
        self.setup.pack()
        self.punchline = tkinter.Label(self.main, textvariable=self.punchlineVar, fg="grey", font=("Arial",14,"italic"), wraplengt=500)
        self.punchline.pack()
        if self.data[self.currentJoke]["numOfRatings"] == 0:
            self.ratings = tkinter.Label(self.main, text="This joke currently has no ratings!", fg="black")
            self.ratings.pack()
        else:
            self.jokeInfo = tkinter.Frame(self.main)
            self.numRatings = tkinter.StringVar()
            self.avgRatings = tkinter.StringVar()
            self.ratings1Var = tkinter.StringVar()
            self.ratings3Var = tkinter.StringVar()
            self.ratings5Var = tkinter.StringVar()
            self.noRatingsVar = tkinter.StringVar()
            self.noRatingsVar.set("")
            self.ratings1Var.set("Rated :")
            self.ratings3Var.set("time(s). Average rating is:")
            self.ratings5Var.set("/5.")
            self.numRatings.set(self.data[self.currentJoke]["numOfRatings"])
            self.avgRatings.set(round(self.data[self.currentJoke]["sumOfRatings"]/self.data[self.currentJoke]["numOfRatings"], 1))
            self.ratings1 = tkinter.Label(self.jokeInfo, textvariable=self.ratings1Var, fg="black", padx=0)
            self.ratings2 = tkinter.Label(self.jokeInfo, textvariable=self.numRatings, fg="black", padx=0)
            self.ratings3 = tkinter.Label(self.jokeInfo, textvariable=self.ratings3Var, fg="black", padx=0)
            self.ratings4 = tkinter.Label(self.jokeInfo, textvariable=self.avgRatings, fg="black", padx=0)
            self.ratings5 = tkinter.Label(self.jokeInfo, textvariable=self.ratings5Var, fg="black", padx=0)
            self.noRatings = tkinter.Label(self.main, textvariable=self.noRatingsVar, fg="black", padx=0)
            self.ratings1.pack(side="left")
            self.ratings2.pack(side="left")
            self.ratings3.pack(side="left")
            self.ratings4.pack(side="left")
            self.ratings5.pack(side="left")
            self.noRatings.pack()
            self.jokeInfo.pack()

    def rateJoke(self):
        self.ratingFrame = tkinter.Frame(self.main)
        self.yourRatingPrompt = tkinter.Label(self.ratingFrame, text="Your Rating:", fg="black")
        self.yourRatingPrompt.pack(side="left")
        self.ratingEntry = tkinter.Entry(self.ratingFrame, width=5)
        self.ratingEntry.pack(side="left")
        self.submitEntry = tkinter.Button(self.ratingFrame, text='submit', relief="groove", command=self.submit)
        self.submitEntry.pack(side="left")
        self.ratingFrame.pack(side="bottom")
        self.ratingEntry.focus_set()

    def submit(self):
        newRating = self.ratingEntry.get()
        if (isinstance(newRating, int) == False):
            try:
                newRating = int(newRating)
            except:
                newRating = ""
                tkinter.messagebox.showinfo("Invalid", "Invalid rating.\nPlease enter an integer between 0 and 5")

        if newRating != "":
            if (-1 < newRating < 6):
                self.data[self.currentJoke]["numOfRatings"] = self.data[self.currentJoke]["numOfRatings"] + 1
                self.data[self.currentJoke]["sumOfRatings"] = self.data[self.currentJoke]["sumOfRatings"] + newRating
                self.currentJoke = self.currentJoke + 1
                with open('data.txt', 'w') as d:
                    json.dump(self.data, d)
                if self.currentJoke < len(self.data):
                    tkinter.messagebox.showinfo("Rating Recorded", "Thank you for ratinging.\nThe next joke will appear now")
                    self.ratingEntry.delete(0, 'end')
                    self.setupVar.set(self.data[self.currentJoke]["setup"])
                    self.punchlineVar.set(self.data[self.currentJoke]["punchline"])
                    if self.data[self.currentJoke]["numOfRatings"] > 0:
                        self.numRatings.set(self.data[self.currentJoke]["numOfRatings"])
                        self.avgRatings.set(round(self.data[self.currentJoke]["sumOfRatings"]/self.data[self.currentJoke]["numOfRatings"], 1))
                    else:
                        self.numRatings.set("")
                        self.avgRatings.set("")
                        self.ratings1Var.set("")
                        self.ratings3Var.set("")
                        self.ratings5Var.set("")
                        self.noRatingsVar.set("This joke currently has no ratings!")
                else:
                    tkinter.messagebox.showinfo("Rating Recorded", "Thank you for rating.\nThat was the last joke.\nThe Program will now end.")
                    exit()
            else:
                newRating = ""
                tkinter.messagebox.showinfo("Invalid", "Invalid entry, please select an entry between 0 and 5")
# Create an object of the ProgramGUI class to begin the program.
gui = ProgramGUI()


import cv2
import numpy as np
import glob

NIR = glob.glob("C:/Users/Skanda/Documents/Machine learning/AgricultureMultispectral/Clipped_NDVI/NIR/*.tif")
IR = glob.glob("C:/Users/Skanda/Documents/Machine learning/AgricultureMultispectral/Clipped_NDVI/IR/*.tif")

k = 0
for nir,ir in zip(NIR,IR):

    img_nir = cv2.imread(nir)
    img_ir = cv2.imread(ir)

    img_nir = img_nir[:,:,0]
    img_ir = img_ir[:,:,0]

    m,n = img_nir.shape

    ndvi = np.where((img_nir+img_ir) == 0,0,(img_nir-img_ir)/(img_nir+img_ir))

    img = np.zeros((m,n,3),dtype=float)

    for i in range(m):
        for j in range(n):

            if ndvi[i,j] > 0.45:
                img[i,j,0] = 0
                img[i,j,1] = 100
                img[i,j,2] = 0

            elif ndvi[i,j] > 0.1:
                img[i,j,0] = 144
                img[i,j,1] = 238
                img[i,j,2] = 144

            elif ndvi[i,j] > -0.5:
                img[i,j,0] = 0
                img[i,j,1] = 75
                img[i,j,2] = 150

            else:
                img[i,j,0] = 255
                img[i,j,1] = 255
                img[i,j,2] = 255

    cv2.imwrite("./process2/img"+str(k)+".jpg",img)
    #cv2.imshow("proc",img/255)

    cv2.waitKey()

    k += 1

#cv2.destroyAllWindows()


import pandas as pd
import numpy as np
import platform
import matplotlib.pyplot as plt

path = "C:/Windows/Fonts/210 맨발의청춘L.ttf"
from matplotlib import font_manager, rc
font_name = font_manager.FontProperties(fname=path).get_name()
rc("font",family=font_name)

population = pd.read_excel("C:/Users/jaeyun/Desktop/github/data_analysis/5.Population/data/edit_data.xlsx",engine='openpyxl',index_col=0)

si_name = [None]*len(population)
tmp_gu_dict = {"수원":["장안구","권선구","팔달구","영통구"],
               "성남":["수정구","중원구","분당구"],
               "안양":["만안구","동안구"],
               "안산":["상록구","단원구"],
               "고양":["덕양구","일산동구","일산서구"],
               "용인":["처인구","기흥구","수지구"],
               "청주":["상당구","서원구","흥덕구","청원구"],
               "천안":["동남구","서북구"],
               "전주":["완산구","덕진구"],
               "포항":["남구","북구"],
               "창원":["의창구","성산구","진해구","마산합포구","마산회원구"],
               "부천":["오정구","원미구","소사구"]}

for n in population.index:
    if population["광역시도"][n][-3:] not in ["광역시","특별시","자치시"]:
        if population["시도"][n][:-1] == "고성" and population["광역시도"][n] == "강원도":
            si_name[n] = "고성(강원)"
        elif population["시도"][n][:-1] == "고성" and population["광역시도"][n] == "경상남도":
            si_name[n] = "고성(경남)"
        else:
            si_name[n] = population["시도"][n][:-1]

        for keys, values in tmp_gu_dict.items():
            if population["시도"][n] in values:
                if len(population["시도"][n]) == 2:
                    si_name[n] = keys + ' ' + population["시도"][n]
                elif population["시도"][n] in ["마산합포구","마산회원구"]:
                    si_name[n] = keys + ' ' + population["시도"][n][2:-1]
                else:
                    si_name[n] = keys + ' ' + population["시도"][n][:-1]
    elif population["광역시도"][n] == "세종특별자치시":
        si_name[n] = "세종"
    else:
        if len(population["시도"][n]) == 2:
            si_name[n] = population["광역시도"][n][:2] + " " + population["시도"][n]
        else:
            si_name[n] = population["광역시도"][n][:2] + " " + population["시도"][n][:-1]

population["ID"] = si_name

del population["20-39세남자"]
del population["65세이상남자"]
del population["65세이상여자"]

draw_korea = pd.read_excel("C:/Users/jaeyun/Desktop/github/data_analysis/5.Population/data/draw_korea_raw.xlsx",engine='openpyxl')
draw_korea_stacked = pd.DataFrame(draw_korea.stack())
draw_korea_stacked.reset_index(inplace=True)
draw_korea_stacked.rename(columns={"level_0":"y", "level_1":"x", 0:"ID"},inplace=True)

draw_korea = draw_korea_stacked
BORDER_LINES = [
    [(5, 1), (5,2), (7,2), (7,3), (11,3), (11,0)], # 인천
    [(5,4), (5,5), (2,5), (2,7), (4,7), (4,9), (7,9),
     (7,7), (9,7), (9,5), (10,5), (10,4), (5,4)], # 서울
    [(1,7), (1,8), (3,8), (3,10), (10,10), (10,7),
     (12,7), (12,6), (11,6), (11,5), (12, 5), (12,4),
     (11,4), (11,3)], # 경기도
    [(8,10), (8,11), (6,11), (6,12)], # 강원도
    [(12,5), (13,5), (13,4), (14,4), (14,5), (15,5),
     (15,4), (16,4), (16,2)], # 충청북도
    [(16,4), (17,4), (17,5), (16,5), (16,6), (19,6),
     (19,5), (20,5), (20,4), (21,4), (21,3), (19,3), (19,1)], # 전라북도
    [(13,5), (13,6), (16,6)], # 대전시
    [(13,5), (14,5)], #세종시
    [(21,2), (21,3), (22,3), (22,4), (24,4), (24,2), (21,2)], #광주
    [(20,5), (21,5), (21,6), (23,6)], #전라남도
    [(10,8), (12,8), (12,9), (14,9), (14,8), (16,8), (16,6)], #충청북도
    [(14,9), (14,11), (14,12), (13,12), (13,13)], #경상북도
    [(15,8), (17,8), (17,10), (16,10), (16,11), (14,11)], #대구
    [(17,9), (18,9), (18,8), (19,8), (19,9), (20,9), (20,10), (21,10)], #부산
    [(16,11), (16,13)], #울산
    [(27,5), (27,6), (25,6)],
]

tmp_list = list(set(population["ID"].unique()) - set(draw_korea["ID"].unique()))
for tmp in tmp_list:
    population = population.drop(population[population["ID"]==tmp].index)
population = pd.merge(population, draw_korea, how="left", on=["ID"])

def draw(targetData, blockedMap, cmapname):
    gamma = 0.75
    whitelabelmin = (max(blockedMap[targetData]) -
                     min(blockedMap[targetData])) * 0.25 + \
                    min(blockedMap[targetData])
    datalabel = targetData
    vmin = min(blockedMap[targetData])
    vmax = max(blockedMap[targetData])

    mapdata = blockedMap.pivot_table(index='y', columns='x', values=targetData)
    masked_mapdata = np.ma.masked_where(np.isnan(mapdata), mapdata)

    plt.figure(figsize=(9, 11))
    plt.pcolor(masked_mapdata, vmin=vmin, vmax=vmax, cmap=cmapname,
               edgecolor='#aaaaaa', linewidth=0.5)

    for idx, row in blockedMap.iterrows():
        if len(row['ID'].split()) == 2:
            dispname = '{}\n{}'.format(row['ID'].split()[0], row['ID'].split()[1])
        elif row['ID'][:2] == '고성':
            dispname = '고성'
        else:
            dispname = row['ID']

        if len(dispname.splitlines()[-1]) >= 3:
            fontsize, linespacing = 10.0, 1.1
        else:
            fontsize, linespacing = 11, 1.
        annocolor = 'white' if row[targetData] > whitelabelmin else 'black'
        plt.annotate(dispname, (row['x'] + 0.5, row['y'] + 0.5), weight='bold',
                     fontsize=fontsize, ha='center', va='center', color=annocolor,
                     linespacing=linespacing)

    for path in BORDER_LINES:
        ys, xs = zip(*path)
        plt.plot(xs, ys, c='black', lw=2)
    plt.gca().invert_yaxis()
    plt.axis('off')
    cb = plt.colorbar(shrink=.1, aspect=10)
    cb.set_label(datalabel)
    plt.tight_layout()
    plt.show()

#draw("인구수합계",population,"Blues")
#population["소멸위기지역"] = [1 if con else 0 for con in population["소멸위기지역"]]
#draw("소멸위기지역",population,"Blues")

population_folium = population.set_index("ID")
population_folium.head()

import folium
import json

geo_path = "C:/Users/jaeyun/Desktop/github/data_analysis/5.Population/data/skorea_municipalities_geo_simple.json"
geo_data = json.load(open(geo_path,encoding='utf-8'))

map = folium.Map(location=[36.2002,127.054],zoom_start=7)
map.choropleth(geo_data=geo_data,
               data=population_folium["인구수합계"],
               columns=[population_folium.index, population_folium["인구수합계"]],
               fill_color="YlGnBu",
               key_on="feature.id")

#map.save("C:/Users/jaeyun/Desktop/github/data_analysis/5.Population/data/seoul_map1.html")

map = folium.Map(location=[36.2002,127.054],zoom_start=7)
map.choropleth(geo_data=geo_data,
               data=population_folium["소멸위기지역"],
               columns=[population_folium.index, population_folium["소멸위기지역"]],
               fill_color="PuRd",
               key_on="feature.id")

map.save("C:/Users/jaeyun/Desktop/github/data_analysis/5.Population/data/seoul_map2.html")


def getInvCount(arr, n):
    # import pdb; pdb.set_trace()
    inv_count = 0
    for i in range(n):
        for j in range(i+1, n):
            if (arr[i] > arr[j]):
                inv_count += 1

    return inv_count

# Driver Code
arr = [5, 4, 3, 2, 1]
n = len(arr)
print("Number of inversions are",
              getInvCount(arr, n))


"""
This script is for testing the functionality of the time module
"""
import os

import pandas as pd

from ipa.get_date import get_date

def test_date():
    path_to_train_data = os.path.join("..", "data/raw/questions_date.csv")
    df = pd.read_csv(path_to_train_data, sep=",", header=0, index_col=False,
                     encoding="utf-8")
    df.columns = ["question", "date", "index"]
    print(df.head())

    df[["predicted_date_string", "predicted_date", "predicted_index"]] = df[
        "question"].apply(
        lambda row: pd.Series(get_date(row)))

    correct = 0
    correct_total = 0
    total_dates = 0
    total_dates_predicted = 0
    for question, date, index, predicted_date, predicted_index in zip(
            df["question"], df["date"], df["index"],
            df["predicted_date"], df["predicted_index"]):
        # if date != "[]" and not predicted_date:
        if date != "[]":
            total_dates += 1
        # precision = actual no date, predict have date
        # if date == "[]" and len(predicted_date) > 0:
        #     total_date_predicted += 1
        if date == str(predicted_date):
            correct_total += 1
        if predicted_date:
            total_dates_predicted += 1
            if date == str(predicted_date):
                correct += 1
            else:
                print(question, date, predicted_date)
                print("---------------------------------")

    print("the number of total goal dates: ", correct_total)
    print("the number of correct date with goal dates are existed: ", correct)
    print("the number of total date: ", total_dates)
    print(
        "the number of wrong predicted date, no date actually but have date "
        "in prediction: ",
        total_dates_predicted)
    print("the total number of questions: ", len(df["question"]))
    accuracy = round(correct_total / len(df["question"]), 2)
    recall = round(correct / total_dates, 2)
    precision = round(correct / total_dates_predicted, 2)
    print("Recall:", recall)
    print("Precision:", precision)
    print('F1 score:', round(2 * precision * recall / (precision + recall), 2))

    print("Accuracy:", accuracy)
    assert accuracy > 0.95

if __name__ == "__main__":
    test_date()