"""
UI Main window functionality
"""
import sys
import os
import cv2
import pickle
import threading
import numpy as np
import PyQt5.QtGui as QtGui
import PyQt5.QtCore as QtCore
import PyQt5.QtWidgets as QtWidgets

import vat_core as vc
import vat_widgets as vw
import vat_utilities as vu
import vat_fixtracking as vft
import vat_ui_warnings as vuw
import vat_experimentconfig as vec
##
##
##
##
class MainWindow(QtWidgets.QMainWindow):
	#######################################################################
	# Main UI class with both app and ui functionality.
	# Serves as a centerpoint and parent to other widgets
	#######################################################################
	# Define signals
	frameTuple = QtCore.pyqtSignal(int, int)	# An integer 2-tuple that contains current frame index and total frame count
	update_combos = QtCore.pyqtSignal()			# Command to update and re-render comboboxes
	log_now = QtCore.pyqtSignal()				# Commnad to take current state of comboboxes in BehaviorSelectorWidget object
												# and save them as attributes
	def __init__(self, parent=None):
		# Does essential startup by instantiating necessary widget classes,
		# setting ui elements and callbacks
		#######################################################################
		super(MainWindow, self).__init__(parent)

		# Create instances of necessary widget classes
		self._initialize_widgets()

		# Define mainwindow layout
		_widget = QtWidgets.QWidget()
		_layout = QtWidgets.QHBoxLayout(_widget)

		# Only imagewidget and behavior_selector_widget are in layout, other
		# widgets mentioned above are conditionally-displayed dialogs
		_layout.addWidget(self.image_widget)
		_layout.addWidget(self.behavior_selector_widget)
		self.setCentralWidget(_widget)

		# Add file menu with necessary actions such as save and new
		self._add_filemenu()

		# Set callbacks for the main widgets (image and behavior selector)
		self._set_widget_callbacks()

		# Initialize indices and other startup variables
		self.currentFrame = 1
		self.n_frames = 0
		self.frameLabel = '{} / {}'.format(self.currentFrame+1, self.n_frames)
		self.mainWidgetShowsTrack = True
		self.colorMap = [(153,255,153),(204,255,153),(255,153,255),(204,153,255),(51,51,255),(51,153,255),(51,255,255),(51,255,153),(255,51,255),(153,51,255),(153,153,255),(153,204,255),(255,255,153),(255,204,153),(255,153,204),(51,255,51),(153,255,51),(255,255,51),(255,153,51),(255,51,51),(255,51,153),(153,255,255),(153,255,204),(0,0,204),(0,204,102),(204,204,0),(204,102,0),(153,153,0),(0,204,0),(153,0,153)]
		self.setFixedSize(1250,1000)
		self.warned = False
		self.wrote_patch_mask = False
		self.attempt = 0
##
##
##
	def _initialize_widgets(self):
		# Makes instances of necessary widgets and saves them as attributes
		#######################################################################
		# Initial configuration manager
		self.experiment_configurator = vec.ExperimentConfigWindow()

		# Dialog to manager user fixing of automatic tracking reads
		self.tracking_fixer = vft.FixTrackingWindow(self)

		# Manges dropdowns for behavior, sex, courting partner, species
		self.behavior_selector_widget = vw.BehaviorSelectorWidget(self)

		# Manages display&update to main ui image
		self.image_widget = vw.ImageWidget(self)
##
##
##
	def _add_filemenu(self):
		# Creates filemenu with save/new actions and adds to MainWindow
		#######################################################################
		# Define actions across top action bar
		newAct = QtWidgets.QAction('New Analysis', self)

		# Set callback for New Analysis option
		newAct.triggered.connect(self.new_analysis_cascade)
		self.experiment_configurator.got_values.connect(self.load_info)
		menubar = self.menuBar()

		# Add New analysis option to File menu
		fileMenu = menubar.addMenu('File')
		fileMenu.addAction(newAct)

		# Add save analysis to file menu, set its callback
		saveAct = QtWidgets.QAction('Save Analysis', self)
		saveAct.triggered.connect(self.save_analysis)
		fileMenu.addAction(saveAct)

		# Add save analysis to file menu, set its callback
		loadAct = QtWidgets.QAction('Load from Last Break', self)
		loadAct.triggered.connect(self.load_cache)
		fileMenu.addAction(loadAct)
##
##
##
	def _set_widget_callbacks(self):
		# Set callbacks for dropdown menus widget
		#######################################################################
		# Callback to show/hide tracking overlays
		self.behavior_selector_widget.toggleTrack.connect(self.toggle_image)

		# Callback to take data from dropdowns and save it as attribute to storage class' behavior_list objects
		self.behavior_selector_widget.newListofBehaviors.connect(self.update_list_of_behaviors)

		# Callback to display fix tracking dialog
		self.behavior_selector_widget.fix_now.connect(self.fix_tracking)

		# Callback to save current data to pickle cache
		self.behavior_selector_widget.signal_save.connect(self.save_to_cache)

		# Callback to emit from log_now signal, which starts the log_entries routine
		self.image_widget.signal_save.connect(self.send_log_now)

		# Callback to connect the imagewidgets request for index (current frame/n_frames)
		# with this widgets function to send index
		self.image_widget.request_frame_status.connect(self.send_frame_status)
##
##
##

	def check_and_warn(self):
		# Check to ensure if all frames and all animals within each frame have been accounted for
		# self.warned 'latches' and will only show warning once as it is a non-critical error
		#######################################################################
		if self.warned==False:
			frame_warn = False
			id_warn = False

			# Initialize warning as an empty list and add strings based on the
			# categories of present errors
			warning = []

			# Iterate through FrameInformation objects
			for frame in self.video_information.get_frame_list():

				# If warning already happened, pass
				if id_warn == True:
					pass

				else:
					# If in the current frame, not all animals have been accounted
					# for, add this message
					if len(frame.list_of_contour_points)<self.n_animals:
						id_warn = True
						warning.append('There are frames where the number of tracked animals is less than {}'.format(self.n_animals))

				# If not all fraames have been analyzed, add this message
				if frame.list_of_contour_points==[] and frame_warn == False:
					frame_warn = True
					warning.append('There are frames that were not visited')
			msg=''

			# Append warning messages and construct a single string to display
			for warn in warning:
				msg = msg + warn + '\n\n'
			msg = msg + 'You may still save, but the unvisited frames will not be represented in the output CSV'

			# Create / show an instance of the Warnin object
			if frame_warn or id_warn:
				self.warning = vuw.WarningMsg(msg)
				self.warning.show()
			self.warned = True
		self.attempt += 1
##
##
##
	def save_analysis(self):
		# End-of-analysis save routine
		# Write data to pickle and create readable output csv and graphics
		#######################################################################
		try:
			self.name

			# Make sure all frames / animals accounted for
			self.check_and_warn()

			# Give one warning and then save away
			if self.warned and self.attempt==1:
				pass

			else:
				# If the last/current frame hasn't been cached, send signal to do so
				if self.active_frame_info.saved==False:
					self.send_log_now()

				# Dump the VideoInformation storage container to a pickle
				with open(os.path.join(os.getcwd(), 'data','{}/{}.pkl'.format(self.name,self.name)), 'wb') as f:
					pickle.dump(self.video_information, f)
				picklename = os.path.join(os.getcwd(), 'data','{}/{}.pkl'.format(self.name,self.name))

				# Create an instance of the DataWriter object
				dw = vu.DataWriter(picklename)

				# Generate informative rows using the DataWriter make_rows method
				dw.make_rows()

				# Write rows to output format using the DataWriter write_csv method
				dw.write_csv()

		except AttributeError:
			# Throw error if a configured experiment does not exist
			msg = 'You must configure a new experiment in order to save'
			self.error = vuw.ErrorMsg(msg)
			self.error.show()
##
##
##
	@QtCore.pyqtSlot()
	def send_log_now(self):
		# Utility to emit the log_now signal, which invokes log_entries routine
		#######################################################################
		self.log_now.emit()
##
##
##
	def make_data_folder(self):
		# Startup utility function to check if data and experiment_cache folders
		# exist, and make them if not
		#######################################################################
		# Make data folder if it doesnt exist
		if 'data' not in os.listdir(os.getcwd()):
			os.mkdir(os.path.join(os.getcwd(), 'data'))

		# Make experiment_cache folder if it doesnt exist
		if 'experiment_cache' not in os.listdir(os.getcwd()):
			os.mkdir(os.path.join(os.getcwd(), 'experiment_cache'))

		# Make a name attribute that is the video name with no file extensions
		self.name = (self.video_address.split('/')[-1]).split('.')[0]

		# If that names is not in the data folder, make a folder for it to store stuff
		if self.name not in os.listdir(os.path.join(os.getcwd(), 'data')):
			os.mkdir(os.path.join(os.getcwd(), 'data', self.name))

		# If there is no labelled_photos folder, make that
		if 'labelled_photos' not in os.listdir(os.path.join(os.getcwd(), 'data', self.name)):
			os.mkdir(os.path.join(os.getcwd(), 'data', self.name,'labelled_photos'))
##
##
##
	@QtCore.pyqtSlot()
	def save_to_cache(self):
		# Sets the metadata's last-analyzed-frame to the current frame,
		# and saves all information to a pickle. Called every time a frame is advanced
		# in the analysis
		#######################################################################
		# We do this before saving so the metadata dictionary will reflect progress
		self.video_information.metadata['last_frame'] = self.currentFrame

		# Dump the VideoInformation storage object into a pickle
		with open(os.path.join(os.getcwd(), 'experiment_cache','cache.pkl'), 'wb') as f:
			pickle.dump(self.video_information, f)
##
##
##
	def load_cache(self):
		# Opens the pickle in the experiment_cache, and populates attributes with
		# the contents to the metadata dictionary. USed to load a past Analysis
		# or recover progress from a crash
		#######################################################################
		try:
			with open(os.path.join(os.getcwd(), 'experiment_cache','cache.pkl'), 'rb') as f:
				self.video_information = pickle.load(f)
				self.currentFrame = 1
				self.thresh = self.video_information.metadata['thresh']
				self.bg = self.video_information.metadata['bg']
				self.large = self.video_information.metadata['large']
				self.small = self.video_information.metadata['small']
				self.solidity = self.video_information.metadata['solidity']
				self.extent = self.video_information.metadata['extent']
				self.aspect = self.video_information.metadata['aspect']
				self.arc = self.video_information.metadata['arc']
				self.video_address = self.video_information.metadata['video_address']
				self.n_patches = self.video_information.metadata['n_patches']
				self.n_animals = self.video_information.metadata['n_animals']
				self.n_frames = self.video_information.metadata['n_frames']
				self.bowl_mask = self.video_information.metadata['bowl_mask']
				self.food_patch_mask = self.video_information.metadata['food_patch_mask']
				self.food_patch_centroids = self.video_information.metadata['food_patch_centroids']
				self.mask_centroid = self.video_information.metadata['mask_centroid']
				self.include_sex = self.video_information.metadata['include_sex']
				self.n_species = self.video_information.metadata['n_species']
				self.chamber_d = self.video_information.metadata['chamber_d']
				self.include_courting_partner = self.video_information.metadata['include_courting_partner']
				self.currentFrame = self.video_information.metadata['last_frame']
				self.warned = False
				self.attempt = 0

			# Make data folder and Initialize video capture object
			self.make_data_folder()
			self.get_cap()

			# Set which dropdowns will be included in the behavior_selector_widget
			self.behavior_selector_widget.set_include_sex_and_species(self.include_sex, self.n_species, self.include_courting_partner)
			self.behavior_selector_widget.adjust_size_widgets(self.n_animals)

			# Initializes frame indices, count (0/N), and shows the current frame in ImageWidget matrix
			self._get_spaced_frames(self.n_frames)
			self.send_frame_status('')
			self.update_raw_image(True)

		except (KeyError, FileNotFoundError) as err:
			msg = 'Could not properly load a cached experiment. Start a new analysis and try again.'
			self.warning = vuw.WarningMsg(msg)
			self.warning.show()

##
##
##
	@QtCore.pyqtSlot(str)
	def send_frame_status(self, id):
		# Increment or decrement the current frame index and update
		# frame progress label.
		#######################################################################
		# If action id = 'inc', increment the frame count unless it exceeds
		# the number of frames intended to be analyzed. Invoked with >> button
		if id=='inc':
			self.currentFrame += 1
			if self.currentFrame > self.n_frames:
				self.currentFrame = self.n_frames

		# If action id = 'dec', decrement the frame count unless it is
		# less than 1. Invoked with << button
		elif id == 'dec':
			self.currentFrame -= 1
			if self.currentFrame < 1:
				self.currentFrame= 1
		else:
			pass

		# After making necessary inc/dec changes, update the current index attribute
		self.currentFrameIndex = self.frameIdxs[self.currentFrame-1]
		if self.currentFrame==self.n_frames:
			self.currentFrameIndex = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT)-300)

		# Send to the ImageWidget a 2-tuple of current frame and nummber of Frames
		# as a means of progress through the analaysis
		self.frameTuple.emit(self.currentFrame, self.n_frames)

		# Set the videocapture object to the video frame referenced by the current index
		self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.currentFrameIndex)

		# Make an attribute for mainwindow to remember that the ImageWidget will be showing tracking
		self.mainWidgetShowsTrack=True

		# Re-render frame after making changes to index
		self.update_raw_image(True)

		# Emit command to update comboboxes for new frame
		self.update_combos.emit()
##
##
##
	def track_raw_image(self):
		# Performs automatic tracking on the current frame and draws necessary overlays
		#######################################################################
		# Define local utility function
		def _get(cnt):
			# Takes cv2.contour type "cnt" as input and computes various statistics
			# to be used for filtering, based on filtering thresholds set during
			# initial configuration
			x,y,w,h = cv2.boundingRect(cnt)
			area = cv2.contourArea(cnt)
			rect_area = w*h
			extent = float(area)/rect_area
			aspect_ratio = float(w)/h
			hull = cv2.convexHull(cnt)
			hull_area = cv2.contourArea(hull)
			if hull_area >0:
				solidity = float(area)/hull_area
			else:
				solidity=100000
			if area==0:
				arc = 1000
			else:
				arc = (cv2.arcLength(cnt,True)/cv2.contourArea(cnt))
			return aspect_ratio, extent, solidity, cv2.contourArea(cnt), arc

		# If the frames has not been tracked yet, perform the automatic contour detection/filter routine
		if self.active_frame_info.tracked==False:
			# Copy and convert to black and white
			self.tracked_image = self.currentRawImage.copy()
			self.tracked_image = cv2.cvtColor(self.tracked_image, cv2.COLOR_BGR2GRAY)

			# Subtract background and increase all channels slightly
			self.tracked_image=self.tracked_image-self.bg + 10
			height = self.currentRawImage.shape[0]

			# Grab appropriately-sized chunk (matching size of analysis frame) of the bowl mask matrix
			self.bm = cv2.cvtColor(self.bowl_mask[:, (self.mask_centroid[0]-int(height/2)):(self.mask_centroid[0]+int(height/2)),:], cv2.COLOR_BGR2GRAY)

			# Apply logical masking on image using the background mask bm
			self.tracked_image = cv2.bitwise_and(self.tracked_image, self.bm)

			# Perform binary threshold on masked/modified image to get black/white
			_,self.threshed_frame = cv2.threshold(self.tracked_image,self.thresh,255,cv2.THRESH_BINARY)

			# Invert
			self.imagem = cv2.bitwise_not(self.threshed_frame)

			# Perform cv2 contour detection algo
			self.contours, hier = cv2.findContours(self.imagem, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

			# Filter contours based on attributes, save valid one to valids list attribute
			self.valids = [cnt for cnt in self.contours if (_get(cnt)[3] > self.small) and (_get(cnt)[3] < self.large) and _get(cnt)[0] < self.aspect and _get(cnt)[1] < self.extent and _get(cnt)[2] > self.solidity and _get(cnt)[-1]<self.arc]

			# Shallow copy current raw image as display frame, for drawing
			# Copy is necessary so drawing actions are not persistent with the raw image frame
			self.display_frame = self.currentRawImage

			# For the list of valid contours, get x/y positions of centroids using mass moment of intertia,
			# assuming pixels have small identical masses
			for idx, c in enumerate(self.valids):
				M = cv2.moments(c)
				if M['m00'] != 0:
					cx = np.float16(M['m10']/M['m00'])
					cy = np.float16(M['m01']/M['m00'])

					# Save x/y coordinate info into ContourPoint storage class
					contour_pt = vc.ContourPoint(idx+1, cx, cy, c, 1)

					# Save the newly created ContourPoint object to the current FrameInformation storage object
					self.active_frame_info.add_contour_point(contour_pt)

					# Draw an outline aroung each valid animal contour in a different color on the display_frame mat
					self.display_frame = cv2.drawContours(self.display_frame, [self.valids[idx]], -1, self.colorMap[idx], 1)

					# Draw the id number of each animal contour in a different color on the display_frame mat
					self.display_frame = cv2.putText(self.display_frame,"{}".format(contour_pt.id),(int(cx+10),int(cy+10)), cv2.FONT_HERSHEY_PLAIN, 2, self.colorMap[idx], thickness = 2)
			self.active_frame_info.tracked = True

		else:
			# If frame has already been tracked, load the list of ContourPoints associated
			# with the current FrameInformation object.
			self.display_frame = self.currentRawImage
			for idx, c in enumerate(self.active_frame_info.get_list_of_contour_points()):

				# See if any labels need spatial reconfiguration to not overlap
				if c.label_config==1:
					xp, yp = 10,10
				elif c.label_config==2:
					xp, yp = -10,-10
				elif c.label_config==3:
					xp, yp = 10,-10
				elif c.label_config==4:
					xp, yp = -10,10

				if c.c is not None:
					# if the contour is not a nonetype (meaning it was tracked automatically),
					# draww a perimeter around each valid animal contour and add add a text ID label
					self.display_frame = cv2.drawContours(self.display_frame, [c.c], -1, self.colorMap[idx], 1)
					self.display_frame = cv2.putText(self.display_frame,"{}".format(c.id),(int(c.x+xp),int(c.y+yp)), cv2.FONT_HERSHEY_PLAIN, 2, self.colorMap[idx], thickness = 2)

				else:
					# if the contour IS a nonetype, meaning it was added manually at some point
					# with the fix_tracking functionality, there is no perimeter to draw so a point is
					# added at the x/y coordinate and a text id label is added as well
					self.display_frame = cv2.circle(self.display_frame,(c.x,c.y),4,self.colorMap[idx],1)
					self.display_frame = cv2.putText(self.display_frame,"{}".format(c.id),(int(c.x+xp),int(c.y+yp)), cv2.FONT_HERSHEY_PLAIN, 2, self.colorMap[idx], thickness = 2)

		# Write the labelled photo to the labelled_photos folder each time it is modified or a new one is created
		cv2.imwrite(os.path.join(os.getcwd(), 'data', self.name,'labelled_photos','{}.jpg'.format(self.active_frame_info.index)),self.display_frame)

		if self.food_patch_mask is not None and not self.wrote_patch_mask:
			cv2.imwrite(os.path.join(os.getcwd(), 'data', self.name,'labelled_photos','{}_food_mask.jpg'.format(self.active_frame_info.index)),self.display_frame*self.food_patch_mask)
			self.wrote_patch_mask = True
##
##
##
	@QtCore.pyqtSlot()
	def update_list_of_behaviors(self):
		# Bring unsaved status of dropdowns to be saved in persistent storage
		# containers. Both tracked positions and qualitative label assessments
		#######################################################################
		# Indicate that the dropdowns for this frame have been saved
		self.active_frame_info.saved = True
		self.behavior_selector_widget.saved_indicator.setStyleSheet('background-color: green')

		# Copy the list of dropdown statuses and x/y's from the behavior_selector_widget to the
		# behavior list attribute of the current FrameInformation object
		self.active_frame_info.behavior_list = self.behavior_selector_widget.list_of_behaviors
		self.active_frame_info.position_list = [[e.id, e.x, e.y] for e in self.active_frame_info.list_of_contour_points]
##
##
##
	def update_raw_image(self, tracking=True):
		# Save the current state of things and update the image in the uis
		# main label with tracking overlays (or not)
		#######################################################################
		# Get the current FrameInformation object
		self.active_frame_info = self.video_information.get_frame_list()[self.currentFrame-1]

		# Display the indicator label based on saved status
		if self.active_frame_info.saved:
			self.behavior_selector_widget.saved_indicator.setStyleSheet('background-color: green')
		else:
			self.behavior_selector_widget.saved_indicator.setStyleSheet('background-color: red')

		# Set the VideoCapture object to the correct frame index and read a frame
		self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.currentFrameIndex)
		_, self.currentRawImage = self.cap.read()
		height = self.currentRawImage.shape[0]

		# Crop out the desired area and mask
		self.currentRawImage = self.currentRawImage[:, (self.mask_centroid[0]-int(height/2)):(self.mask_centroid[0]+int(height/2)),:]
		self.currentRawImage = cv2.bitwise_and(self.currentRawImage, self.bowl_mask[:, (self.mask_centroid[0]-int(height/2)):(self.mask_centroid[0]+int(height/2)),:])

		# Call ImageWidget object's function to update the label,
		# with or without tracking based on desired condition
		if tracking==True:
			self.track_raw_image()
			self.image_widget.setLabel(self.display_frame)
		else:
			self.image_widget.setLabel(self.currentRawImage)
##
##
##
	@QtCore.pyqtSlot()
	def toggle_image(self):
		# Flips the state of whether or not the main ImageWidget is showing tracking overlays
		#######################################################################
		cv2.destroyAllWindows()
		if self.mainWidgetShowsTrack==True:

			# Saves entries before modifying, was resetting to defaults without this
			self.log_now.emit()

			# Call to update ImageWidget without overlays
			self.update_raw_image(False)
			self.mainWidgetShowsTrack=False

		else:
			# Call to update ImageWidget with overlays
			self.update_raw_image(True)
			self.mainWidgetShowsTrack=True
##
##
##
	def test_last_frame(self):
		# Hacky check. When grabbing a frame by index using the cv2.CAP_PROP_POS_FRAMES
		# attribute, the last frame is often erroneous. Want to know what the last frame
		# corresponding to a valid matrix is.
		#######################################################################
		# Until proven Otherwise, assume cv2.CAP_PROP_POS_FRAMES gave a good result
		done = False
		lastFrame = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))

		while not done:
			try:
				# Check if settng capture to last frame and reading throws exception
				self.cap.set(cv2.CAP_PROP_POS_FRAMES,lastFrame)
				_, r = self.cap.read()
				r.shape
				done=True
				return lastFrame

			except AttributeError:
				# If exception thrown, move back by 1 second. Repeat until valid
				# frame is grabbed
				lastFrame = lastFrame - 30
##
##
##
	def _get_spaced_frames(self, depth):
		# Get a list of length: depth spaced indices for grabbing frames in analysis
		#######################################################################
		# Perform check to get last valid frame
		lastFrame = self.test_last_frame()

		# Calcluate a depth-dimensional evenly spaced array, and save as a list
		self.frameIdxs = np.linspace(0, lastFrame, num=depth)
		self.frameIdxs = [int(e) for e in self.frameIdxs]
##
##
##
	@QtCore.pyqtSlot()
	def fix_tracking(self):
		# Display the fix_tracking dialog window
		#######################################################################
		self.tracking_fixer.show()
		self.tracking_fixer.move((self.x() + self.width()) / 2, (self.y() + self.height()) / 2)
##
##
##
	def get_cap(self):
		# Create a video capture object with the analysis address
		#######################################################################
		self.cap = cv2.VideoCapture(self.video_address)
##
##
##
	def load_info(self):
		# Load information from ExperimentConfigWindow
		#######################################################################
		# Used ExperimentConfigWindow's get_data() to return all information set there
		vals = self.experiment_configurator.get_values()
		self.thresh = vals['thresh']
		self.large = vals['large']
		self.small = vals['small']
		self.solidity = vals['solidity']
		self.extent = vals['extent']
		self.aspect = vals['aspect']
		self.arc = vals['arc']
		self.bg = vals['bg']
		self.video_address = vals['video_address']
		self.n_patches = vals['n_patches']
		self.n_animals = vals['n_animals']
		self.n_frames = vals['n_frames']
		self.bowl_mask = vals['bowl_mask']
		self.food_patch_mask = vals['food_patch_mask']
		self.food_patch_centroids = vals['food_patch_centroids']
		self.mask_centroid = vals['mask_centroid']
		self.include_sex = vals['include_sex']
		self.n_species = vals['n_species']
		self.chamber_d = vals['chamber_d']
		self.include_courting_partner = vals['include_courting_partner']

		# Store information in the metadata dictionary
		metadata = vals

		# Check to make sure data folders exist
		self.make_data_folder()

		# Reinitialize the cv2 VideoCapture object
		self.get_cap()

		# Based on user entries, render the requested dropdown boxes
		self.behavior_selector_widget.set_include_sex_and_species(self.include_sex, self.n_species, self.include_courting_partner)
		self.behavior_selector_widget.adjust_size_widgets(self.n_animals)

		# Get a list of spaced frames for analysis, based on user-desired number
		self._get_spaced_frames(self.n_frames)

		# Initialize frame index counter, create main data storage class VideoInformation
		self.currentFrameIndex = self.frameIdxs[0]
		self.video_information = vc.VideoInformation(self.video_address, metadata)
		self.video_information.metadata['frameIdxs'] = self.frameIdxs

		# Iterate through the number of desired frames, make a blank FrameInformation
		# data storage object, add it to the VideoInformation object
		for i in range(self.n_frames):
			new_frame = vc.FrameInformation(i+1, self.video_address, self.n_animals, self.frameIdxs[i])
			self.video_information.add_frame(new_frame)

		# Keep frame progress indicator blank for now
		self.send_frame_status('')
##
##
##
	def new_analysis_cascade(self):
		# Display the ExperimentConfigWindow dialog to let user configure
		#######################################################################
		self.experiment_configurator.show()
		self.experiment_configurator.move((self.x() + self.width()) / 2, (self.y() + self.height()) / 2)
##
##
##
def main():
	# Run ui on main thread
	#######################################################################
	app = QtWidgets.QApplication(sys.argv)
	win = MainWindow()
	win.show()
	app.exec_()

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


import time
from torchvision import models, datasets, transforms
import torch
import torch.nn.functional as F
from nasnet.nasnet import NASNetALarge
from nasnet.nasnet_mobile import NASNetAMobile
from utils.sync_control import *

def train_wrapper(sync_info, tid: int, model_config, shared_config):
    device = torch.device("cuda:0")
    my_stream = torch.cuda.Stream(device=device)
    arc = model_config['arc']
    model = NASNetALarge(num_classes=1000) if arc == 'large' else NASNetAMobile(num_classes=1000)
    model = model.to(device)
    model.train()

    train_transform = transforms.Compose([
        transforms.RandomResizedCrop(331 if arc == 'large' else 224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))])

    train_dataset = \
        datasets.ImageFolder(shared_config['imagenet_root'], transform=train_transform)

    train_loader = torch.utils.data.DataLoader(
        train_dataset, batch_size=model_config['batch_size'], shuffle=True, num_workers=model_config['num_workers'])
    metric_fn = F.cross_entropy
    optimizer_func = getattr(torch.optim, model_config['optimizer'])
    optimizer = optimizer_func(model.parameters(), lr=0.001)

    for batch_idx, batch in enumerate(train_loader):
        data, target = batch[0].to(device), batch[1].to(device)
        with ForwardControl(thread_id=tid, batch_idx=batch_idx, sync_info=sync_info, stream=my_stream):
            with torch.cuda.stream(my_stream):
                output = model(data)
                loss = metric_fn(output, target)

        with BackwardControl(thread_id=tid, batch_idx=batch_idx, sync_info=sync_info, stream=my_stream):
            with torch.cuda.stream(my_stream):
                loss.backward()
                optimizer.step()
                optimizer.zero_grad()


# encoding: utf-8
"""
@author:  l1aoxingyu
@contact: sherlockliao01@gmail.com
"""

import os

import torch
from torch._six import container_abcs, string_classes, int_classes
from torch.utils.data import DataLoader

from fastreid.utils import comm
from . import samplers
from .common import CommDataset
from .datasets import DATASET_REGISTRY
from .transforms import build_transforms

_root = os.getenv("FASTREID_DATASETS", "datasets")

def build_reid_train_loader(cfg, mapper=None, **kwargs):
    cfg = cfg.clone()

    train_items = list()
    for d in cfg.DATASETS.NAMES:
        dataset = DATASET_REGISTRY.get(d)(root=_root, combineall=cfg.DATASETS.COMBINEALL, **kwargs)
        if comm.is_main_process():
            dataset.show_train()
        train_items.extend(dataset.train)

    if mapper is not None:
        transforms = mapper
    else:
        transforms = build_transforms(cfg, is_train=True)

    train_set = CommDataset(train_items, transforms, relabel=True)

    num_workers = cfg.DATALOADER.NUM_WORKERS
    num_instance = cfg.DATALOADER.NUM_INSTANCE
    mini_batch_size = cfg.SOLVER.IMS_PER_BATCH // comm.get_world_size()

    if cfg.DATALOADER.PK_SAMPLER:
        if cfg.DATALOADER.NAIVE_WAY:
            data_sampler = samplers.NaiveIdentitySampler(train_set.img_items, mini_batch_size, num_instance)
        else:
            data_sampler = samplers.BalancedIdentitySampler(train_set.img_items, mini_batch_size, num_instance)
    else:
        data_sampler = samplers.TrainingSampler(len(train_set))
    batch_sampler = torch.utils.data.sampler.BatchSampler(data_sampler, mini_batch_size, True)

    train_loader = torch.utils.data.DataLoader(
        train_set,
        num_workers=num_workers,
        batch_sampler=batch_sampler,
        collate_fn=fast_batch_collator,
        pin_memory=True,
    )
    return train_loader

def build_reid_test_loader(cfg, dataset_name, mapper=None, **kwargs):
    cfg = cfg.clone()

    dataset = DATASET_REGISTRY.get(dataset_name)(root=_root, **kwargs)
    if comm.is_main_process():
        dataset.show_test()
    test_items = dataset.query + dataset.gallery

    if mapper is not None:
        transforms = mapper
    else:
        transforms = build_transforms(cfg, is_train=False)

    test_set = CommDataset(test_items, transforms, relabel=False)

    mini_batch_size = cfg.TEST.IMS_PER_BATCH // comm.get_world_size()
    data_sampler = samplers.InferenceSampler(len(test_set))
    batch_sampler = torch.utils.data.BatchSampler(data_sampler, mini_batch_size, False)
    test_loader = DataLoader(
        test_set,
        batch_sampler=batch_sampler,
        num_workers=4,  # save some memory
        collate_fn=fast_batch_collator,
        pin_memory=True,
    )
    return test_loader, len(dataset.query)

def trivial_batch_collator(batch):
    """
    A batch collator that does nothing.
    """
    return batch

def fast_batch_collator(batched_inputs):
    """
    A simple batch collator for most common reid tasks
    """
    elem = batched_inputs[0]
    if isinstance(elem, torch.Tensor):
        out = torch.zeros((len(batched_inputs), *elem.size()), dtype=elem.dtype)
        for i, tensor in enumerate(batched_inputs):
            out[i] += tensor
        return out

    elif isinstance(elem, container_abcs.Mapping):
        return {key: fast_batch_collator([d[key] for d in batched_inputs]) for key in elem}

    elif isinstance(elem, float):
        return torch.tensor(batched_inputs, dtype=torch.float64)
    elif isinstance(elem, int_classes):
        return torch.tensor(batched_inputs)
    elif isinstance(elem, string_classes):
        return batched_inputs


import os
from datetime import date

class ApplicantMenu(object):

    def __init__(self,DB):
        self.DB = DB

    def createNewApplication(self):

        newApplicationMenuState = 'NewApplicationMainMenuState'
        newApplicationMenu = True

        jobApplyDict = {'PositionApplied':'', 'DateApplied':'', 'ExpectedSalary': '', 'Availability': '', 'AcceptJob': '', 'ConfirmJob': ''}
        personalDetailDict = {'Name':'', 'NRIC_Passport':'', 'Address':'', 'PostalCode': '', 'Email': '', 'HomeNo': '', 'MobileNo': '', 'DateOfBirth': '', 'Gender': ''}
        qualificationDict = {'Qualification': '', 'InstitutionUniversity': '', 'Major': '', 'Grade': '', 'YearGraduated': ''}
        workingExperienceDict = {'Company': '', 'Industry': '', 'Position': '', 'FromMonth': '', 'FromYear': '', 'ToMonth': '', 'ToYear': '','Level': '', 'MonthlySalary': ''}
        referenceDict = {'Name': '', 'Occupation': '', 'CompanyOrganization': '', 'ContactNo': '', 'Email': '', 'Relationship': ''}

        today = date.today()

        while newApplicationMenu == True:
            if newApplicationMenuState == 'NewApplicationMainMenuState':
                print('____________________________________________')
                print('1. Job Choice')
                print('2. Personal Details')
                print('3. Qualifications')
                print('4. Working Experiences')
                print('5. References')
                print('6. Submit Application')
                print('7. Go Back')
                optionChosen = input("Select option here: ")
                if optionChosen == "1":
                    newApplicationMenuState = 'JobChoiceState'
                elif optionChosen == "2":
                    newApplicationMenuState = 'PersonalDetailState'
                elif optionChosen == "3":
                    newApplicationMenuState = 'QualificationState'
                elif optionChosen == "4":
                    newApplicationMenuState = 'WorkingExperienceState'
                elif optionChosen == "5":
                    newApplicationMenuState = 'ReferenceState'
                elif optionChosen == "6":
                    newApplicationMenuState = 'FinalConfirmationState'
                elif optionChosen == "7":
                    newApplicationMenu = False;
                else:
                    print("Incorrect input, please try again.")

            elif newApplicationMenuState == 'JobChoiceState':
                jobChoiceMenuState = 'PositionState'
                while jobChoiceMenuState != 'ConfirmedState':
                    if jobChoiceMenuState == 'PositionState':
                        jobApplyDict['PositionApplied'] = input("Enter your preferred job position: ")
                        jobChoiceMenuState = 'SalaryState'

                    elif jobChoiceMenuState == 'SalaryState':
                        jobApplyDict['ExpectedSalary'] = input("Enter your expected salary: ")
                        jobChoiceMenuState = 'AvailbilityState'

                    elif jobChoiceMenuState == 'AvailbilityState':
                        jobApplyDict['Availability'] = input("Enter the number of months you are available: ")
                        jobChoiceMenuState = 'CheckState'

                    elif jobChoiceMenuState == 'CheckState':
                        confirmation = input("Are you sure about your input?\n1 - Yes, 2 - No: ")
                        if confirmation == "1":
                            jobApplyDict['Date'] = today.strftime("%d/%m/%Y")
                            jobApplyDict['AcceptJob'] = "0"
                            jobApplyDict['ConfirmJob'] = "0"
                            jobChoiceMenuState = 'ConfirmedState'
                        elif confirmation == "2":
                            jobChoiceMenuState = 'PositionState'
                        else:
                            print("Incorrect input, please try again.")
                else:
                    newApplicationMenuState = 'NewApplicationMainMenuState'

            elif newApplicationMenuState == 'PersonalDetailState':
                personalDetailMenuState = 'NameState'
                while personalDetailMenuState != 'ConfirmedState':
                    if personalDetailMenuState == 'NameState':
                        personalDetailDict['Name'] = input("Enter the applicant's name: ")
                        personalDetailMenuState = 'NRICState'

                    elif personalDetailMenuState == 'NRICState':
                        personalDetailDict['NRIC_Passport'] = input("Enter your NRIC or Passport No: ")
                        personalDetailMenuState = 'AddressState'

                    elif personalDetailMenuState == 'AddressState':
                        personalDetailDict['Address'] = input("Enter your home address: ")
                        personalDetailMenuState = 'PostCodeState'

                    elif personalDetailMenuState == 'PostCodeState':
                        personalDetailDict['PostalCode'] = input("Enter your postal code: ")
                        personalDetailMenuState = 'EmailState'

                    elif personalDetailMenuState == 'EmailState':
                        personalDetailDict['Email'] = input("Enter your email: ")
                        personalDetailMenuState = 'HomeNoState'

                    elif personalDetailMenuState == 'HomeNoState':
                        personalDetailDict['HomeNo'] = input("Enter your home number: ")
                        personalDetailMenuState = 'MobileNoState'

                    elif personalDetailMenuState == 'MobileNoState':
                        personalDetailDict['MobileNo'] = input("Enter your mobile number: ")
                        personalDetailMenuState = 'DateOfBirthState'

                    elif personalDetailMenuState == 'DateOfBirthState':
                        dateOfBirth = input("Enter the day of your Birth: ")
                        monthOfBirth = input("Enter the month of your Birth: ")
                        yearOfBirth = input("Enter the year of your Birth: ")
                        personalDetailDict['DateOfBirth'] = dateOfBirth + "/" + monthOfBirth + "/" + yearOfBirth
                        personalDetailMenuState = 'GenderState'

                    elif personalDetailMenuState == 'GenderState':
                        genderInput = input("Select your gender:\n1 - Male 2 - Female: ")
                        if genderInput == '1':
                            personalDetailDict['Gender']  = 'Male'
                            personalDetailMenuState = 'CheckState'
                        elif genderInput == '2':
                            personalDetailDict['Gender']  = 'Female'
                            personalDetailMenuState = 'CheckState'
                        else:
                            print("Please enter 1 or 2 only.")

                    elif personalDetailMenuState == 'CheckState':
                        confirmation = input("Are you sure about your application?\n1 - Yes, 2 - No: ")
                        if confirmation == '1':
                            personalDetailMenuState = 'ConfirmedState'
                        elif confirmation == '2':
                            personalDetailMenuState = 'GenderState'
                        else:
                            print("Incorrect input, please try again.")
                else:
                    newApplicationMenuState = 'NewApplicationMainMenuState'

            elif newApplicationMenuState == 'QualificationState':
                qualificationMenuState = 'QualificationState'
                while qualificationMenuState != 'ConfirmedState':
                    if qualificationMenuState == 'QualificationState':
                        qualificationDict['Qualification'] = input("Enter your qualification: ")
                        qualificationMenuState = 'InstitutionUniState'

                    elif qualificationMenuState == 'InstitutionUniState':
                        qualificationDict['InstitutionUniversity'] = input("Enter the Institution or University you've studied in: ")
                        qualificationMenuState = 'MajorState'

                    elif qualificationMenuState == 'MajorState':
                        qualificationDict['Major'] = input("Enter your Major: ")
                        qualificationMenuState = 'GradeState'

                    elif qualificationMenuState == 'GradeState':
                        qualificationDict['Grade'] = input("Enter your GPA that you've obtained: ")
                        qualificationMenuState = 'YearGraduateState'

                    elif qualificationMenuState == 'YearGraduateState':
                        qualificationDict['YearGraduated'] = input("Enter the year you've graduated: ")
                        qualificationMenuState = 'CheckState'

                    elif qualificationMenuState == 'CheckState':
                        confirmation = input("Are you sure about your input?\n1 - Yes, 2 - No: ")
                        if confirmation == "1":
                            qualificationMenuState = 'ConfirmedState'
                        elif confirmation == "2":
                            qualificationMenuState = 'PositionState'
                        else:
                            print("Incorrect input, please try again.")
                else:
                    newApplicationMenuState = 'NewApplicationMainMenuState'

            elif newApplicationMenuState == 'WorkingExperienceState':
                workingExperienceMenuState = 'CompanyState'
                while workingExperienceMenuState != 'ConfirmedState':
                    if workingExperienceMenuState == 'CompanyState':
                        workingExperienceDict['Company'] = input("Enter the name of the company you worked in: ")
                        workingExperienceMenuState = 'IndustryState'

                    elif workingExperienceMenuState == 'IndustryState':
                        workingExperienceDict['Industry'] = input("Enter the name of the industry of the company: ")
                        workingExperienceMenuState = 'PositionState'

                    elif workingExperienceMenuState == 'PositionState':
                        workingExperienceDict['Position'] = input("Enter your position in the job: ")
                        workingExperienceMenuState = 'FromDateState'

                    elif workingExperienceMenuState == 'FromDateState':
                        fromMonth = input("Enter the month when you started: ")
                        fromYear = input("Enter the year when you started: ")
                        workingExperienceDict['FromDate'] = fromMonth + "/" + fromYear
                        workingExperienceMenuState = 'ToDateState'

                    elif workingExperienceMenuState == 'ToDateState':
                        ToMonth = input("Enter the month when you started: ")
                        ToYear = input("Enter the year when you started: ")
                        workingExperienceDict['ToDate'] = ToMonth + "/" + ToYear
                        workingExperienceMenuState = 'LevelState'

                    elif workingExperienceMenuState == 'LevelState':
                        workingExperienceDict['Level'] = input("Enter your job position level: ")
                        workingExperienceMenuState = 'SalaryState'

                    elif workingExperienceMenuState == 'SalaryState':
                        workingExperienceDict['MonthlySalary'] = input("Enter the monthly salary for that job: ")
                        workingExperienceMenuState = 'CheckState'

                    elif workingExperienceMenuState == 'CheckState':
                        confirmation = input("Are you sure about your input?\n1 - Yes, 2 - No: ")
                        if confirmation == "1":
                            workingExperienceMenuState = 'ConfirmedState'
                        elif confirmation == "2":
                            workingExperienceMenuState = 'CompanyState'
                        else:
                            print("Incorrect input, please try again.")
                else:
                    newApplicationMenuState = 'NewApplicationMainMenuState'

            elif newApplicationMenuState == 'ReferenceState':
                referenceMenuState = 'NameState'
                while referenceMenuState != 'ConfirmedState':
                    if referenceMenuState == 'NameState':
                        referenceDict['Name'] = input("Enter the name of the person being referred: ")
                        referenceMenuState = 'OccupationState'

                    elif referenceMenuState == 'OccupationState':
                        referenceDict['Occupation'] = input("Enter the occupation of the referred person: ")
                        referenceMenuState = 'CompanyState'

                    elif referenceMenuState == 'CompanyState':
                        referenceDict['CompanyOrganization'] = input("Enter the company the referred person works at: ")
                        referenceMenuState = 'ContactNoState'

                    elif referenceMenuState == 'ContactNoState':
                        referenceDict['ContactNo'] = input("Enter the contact number of the referred person: ")
                        referenceMenuState = 'EmailState'

                    elif referenceMenuState == 'EmailState':
                        referenceDict['Email'] = input("Enter the email of the referred person: ")
                        referenceMenuState = 'relationshipState'

                    elif referenceMenuState == 'relationshipState':
                        referenceDict['Relationship'] = input("Enter your relationship to this referred person: ")
                        referenceMenuState = 'CheckState'

                    elif referenceMenuState == 'CheckState':
                        confirmation = input("Are you sure about your input?\n1 - Yes, 2 - No: ")
                        if confirmation == "1":
                            referenceMenuState = 'ConfirmedState'
                        elif confirmation == "2":
                            referenceMenuState = 'PositionState'
                        else:
                            print("Incorrect input, please try again.")
                else:
                    newApplicationMenuState = 'NewApplicationMainMenuState'

            elif newApplicationMenuState == 'FinalConfirmationState':
                finalConfirmation = input("Are you sure about submitting your application?\n1 - Yes, 2 - No: ")
                if finalConfirmation == "1":
                    dictList = [jobApplyDict, personalDetailDict, qualificationDict, workingExperienceDict, referenceDict]
                    self.DB.submitNewApplication(dictList)
                    newApplicationMenu = False;
                elif confirmation == "2":
                    newApplicationMenuState = 'NewApplicationMainMenuState'
                else:
                    print("Incorrect input, please try again.")

    @staticmethod
    def reviewSubmittedApplication(self):

        reviewApplicationMenuState = 'ReviewState'

        while reviewApplicationMenuState != 'ConfirmedState':

            if reviewApplicationMenuState == 'ReviewState':
                print("Shoot")

            elif reviewApplicationMenuState == 'ReviewState':
                print('Potato')

        else:
            return None


from itertools import product

def load_instructions(fname):
    with open(fname) as fid:
        lines = fid.readlines()

    instructions = []
    for line in lines:
        if line.startswith('mask'):
            mask = line.split('=')[1].strip()
            instructions.append(('mask', mask))
        elif line.startswith('mem'):
            start = line.index('[') + 1
            stop = line.index(']')
            address = line[start:stop]
            val = line.split('=')[1].strip()
            instructions.append(('mem', int(address), int(val)))
    return instructions

def apply_bit_mask(mask, val):
    bits = '{0:036b}'.format(val)
    bits_out = ''
    for i, m in enumerate(mask):
        if m != 'X':
            bits_out += m
        else:
            bits_out += bits[i]
    return int(bits_out, 2)

def apply_floating_bit_mask(mask, val):
    bits = '{0:036b}'.format(val)
    bits_out = ''
    for i, m in enumerate(mask):
        if m == '0':
            bits_out += bits[i]
        elif m in ['1', 'X']:
            bits_out += m
        else:
            ValueError('Unrecognised value')
    return bits_out

def generate_combos(bits):
    f_indx = [i for i, bit in enumerate(bits) if bit == 'X']

    bits_out_combos = []
    for combo in product(('0','1'),repeat=len(f_indx)):
        new_bits = list(bits)
        for i, b in enumerate(combo):
            new_bits[f_indx[i]] = b
        bits_out_combos.append(''.join(new_bits))

    return [int(b, 2) for b in bits_out_combos]

def run_instructions(instructions):
    mem = {}
    for i in instructions:
        if i[0] == 'mask':
            curr_mask = i[1]
        elif i[0] == 'mem':
            _, addr, val = i
            mem[addr] = apply_bit_mask(curr_mask, val)
        else:
            ValueError('Instruction not recognised, got {i[0]}')
    return mem

def run_instructions2(instructions):
    mem = {}
    for i in instructions:
        if i[0] == 'mask':
            curr_mask = i[1]
        elif i[0] == 'mem':
            _, addr, val = i
            b = apply_floating_bit_mask(curr_mask, addr)
            addrs = generate_combos(b)
            for addr in addrs:
                mem[addr] = val
        else:
            ValueError('Instruction not recognised, got {i[0]}')
    return mem

instructions = load_instructions('advent_day14.txt')
mem = run_instructions(instructions)

print('Part 1')
print(f'Sum of all values in memory = {sum(mem.values())}')

mem = run_instructions2(instructions)
print('Part 2')
print(f'Sum of all values in memory = {sum(mem.values())}')


"""
  Solution managers actually walk a model through all the steps to solve
"""
import multiprocess
import numpy as np

import tqdm

from srlife import solverparams, thermal

def merge_dicts(idict):
    """
    Merge an iterator over dictionaries into a single dict
    """
    return {k: v for d in idict for k, v in d.items()}

class SolutionManager:
    """Solution manager

    High level solution manager walking through the thermal, structural,
    and damage calculations.

    Args:
      receiver (receiver.Receiver): receiver object to solve
      thermal_solver (thermal.ThermalSolver): how to solve the heat transport
      thermal_material (materials.ThermalMaterial): solid thermal properties
      fluid_material (materials.FluidMaterial): fluid thermal properties
      structural_solver (structural.TubeSolver):  how to solve the mechanics problem
      deformation_material (materials.DeformationMaterial):  how things deform with time
      damage_material (materials.StructuralMaterial):  how to calculate creep damage
      system_solver (system.SystemSolver):  how to tie tubes into the structural system
      damage_model (damage.DamageCalculator): how to calculate damage from the results
      pset (Optional[solverparams.ParameterSet]): optional set of solver parameters
    """

    def __init__(
        self,
        receiver,
        thermal_solver,
        thermal_material,
        fluid_material,
        structural_solver,
        deformation_material,
        damage_material,
        system_solver,
        damage_model,
        pset=solverparams.ParameterSet(),
    ):
        self.receiver = receiver
        self.thermal_solver = thermal_solver
        self.thermal_material = thermal_material
        self.fluid_material = fluid_material
        self.structural_solver = structural_solver
        self.deformation_material = deformation_material
        self.damage_material = damage_material
        self.system_solver = system_solver
        self.damage_model = damage_model

        self.pset = pset
        self.nthreads = pset.get_default("nthreads", 1)
        self.progress = pset.get_default("progress_bars", False)

        self.page = pset.get_default("page_results", False)
        self.receiver.set_paging(self.page)

        self.heuristics = []

    def add_heuristic(self, heuristic):
        """Add a heuristic to use during the solve

        Args:
          heuristics (list): new heuristic to add
        """
        self.heuristics.append(heuristic)

    @property
    def tubes(self):
        """Direct iterator over tubes

        Returns:
          iterator over tubes
        """
        return self.receiver.tubes

    @property
    def ntubes(self):
        """Pass through to get the number of tubes that need to be analyzed

        Returns:
          int:  total number of tubes in entire receiver
        """
        return len(list(self.tubes))

    def progress_decorator(self, base, ntotal):
        """Either wrap with a progress bar decorator or return a dummy

        Args:
          base (function): base function to wrap
          ntotal (int): total number in iterator, needed for wrapping iterators

        Returns:
          either function wrapped with decorator or base function
        """
        if self.progress:
            return tqdm.tqdm(base, total=ntotal)
        else:
            return base

    def solve_life(self):
        """User interface: solve everything and return receiver life

        The trigger for everything: solve the complete problem and report the
        best-estimate life.

        Returns:
          float:  Number of allowed daily cycles
        """
        self.solve_heat_transfer()
        self.solve_structural()

        return self.calculate_damage()

    def calculate_damage(self):
        """Calculate damage from the results

        Returns:
          float:    Number of allowed daily cycles
        """
        if self.progress:
            print("Calculating damage:")
        return self.damage_model.determine_life(
            self.receiver,
            self.damage_material,
            nthreads=self.nthreads,
            decorator=self.progress_decorator,
        )

    def solve_reliability(self, time):
        """User interface: solve everything and return receiver reliability

        The trigger for everything: solve the complete problem and report the
        best-estimate reliability.

        Args:
            time (float): time at which to report reliability

        Returns:
          float:  Reliability between 0 and 1
        """
        self.solve_heat_transfer()
        self.solve_structural()

        return self.calculate_reliability(time)

    def calculate_reliability(self, time):
        """Calculate reliability from the results

        Args:
            time (float): time at which to report reliability

        Returns:
          float:    Reliability between 0 and 1
        """
        if self.progress:
            print("Calculating reliability :")
        return self.damage_model.determine_reliability(
            self.receiver,
            self.damage_material,
            time,
            nthreads=self.nthreads,
            decorator=self.progress_decorator,
        )

    def solve_heat_transfer(self):
        """Solve heat transfer for the receiver

        Adds thermal results in each tube
        """
        if isinstance(self.thermal_solver, thermal.ThermohydraulicsThermalSolver):
            if self.progress:
                print("Running thermohydraulic analysis")
            self.thermal_solver.solve_receiver(
                self.receiver,
                self.thermal_material,
                self.fluid_material,
                decorator=self.progress_decorator,
                nthreads=self.nthreads,
                **merge_dicts(
                    h.args_for_thermohydraulic_solver(self.receiver)
                    for h in self.heuristics
                )
            )
        else:
            self.solve_heat_transfer_tube()

    def solve_heat_transfer_tube(self):
        """Solve the heat transfer problem for each tube

        Adds the thermal results to each receiver.Tube object
        """
        # pylint: disable=no-member
        if self.progress:
            print("Running thermal analysis:")
        with multiprocess.Pool(self.nthreads) as p:
            temps = list(
                self.progress_decorator(
                    p.imap(
                        lambda x: self.thermal_solver.solve(
                            x,
                            self.thermal_material,
                            self.fluid_material,
                            **merge_dicts(
                                h.args_for_thermal_solver(self.receiver, x)
                                for h in self.heuristics
                            )
                        ),
                        self.tubes,
                    ),
                    self.ntubes,
                )
            )
        for tube, temps in zip(self.tubes, temps):
            tube.add_results("temperature", temps)

    def solve_structural(self):
        """Solve the structural problem for the complete system

        Adds the structural results to each tube.
        """
        if self.progress:
            print("Running structural analysis:")
        self.system_solver.solve(
            self.receiver,
            self.deformation_material,
            self.structural_solver,
            nthreads=self.nthreads,
            decorator=self.progress_decorator,
            verbose=self.progress,
        )

class Heuristic:
    """Solution heuristic superclass

    Class that defines a heuristic to modify the basic 3D solve process in some
    way.

    To implement a specific heuristic override the appropriate pure virtual
    methods.
    """

    def args_for_tube_thermal_solver(self, receiver, tube):
        """Add tube solver args

        Args:
          receiver (receiver.receiver):       receiver object affected
          tube (receiver.tube):               tube object affected

        """
        return {}

    def args_for_thermohydraulic_solver(self, receiver):
        """Add tube solver args

        Args:
          receiver (receiver.receiver):       receiver object affected

        """
        return {}

class CycleResetHeuristic(Heuristic):
    """
    Reset the tube temperatures each cycle to the initial values
    """

    def args_for_tube_thermal_solver(self, receiver, tube):
        """Modify the tube solver before the solve

        Args:
          receiver (receiver.receiver):       receiver object affected
          tube (receiver.tube):               tube object affected
        """
        resetter = thermal.TemperatureResetter(
            lambda t: np.isclose(t % receiver.period, 0), tube.T0
        )

        return {"resetters": [resetter]}

    def args_for_thermohydraulic_solver(self, receiver):
        """Add tube solver args

        Args:
          receiver (receiver.receiver):       receiver object affected

        """
        resetter = thermal.ReceiverResetter(
            lambda t: np.isclose(t % receiver.period, 0)
        )

        return {"resetters": [resetter]}


from selenium import webdriver
import pyautogui,time
class Duck:
    def __init__(self,driver):

        self.driver=driver
        self.url='https://duckduckgo.com'
        self.search_bar_id="search_form_input_homepage"
        self.search_button="btnK"
        self.first_link_class="result__url__domain"
    def navigate (self):

         self.driver.get(self.url)

    def search(self,nome='None'):
        self.driver.find_element_by_id(self.search_bar_id).send_keys(nome)
        #self.driver.find_element_by_name(self.search_bar).send_keys()
        pyautogui.typewrite('\n')

    def textconvert(self):
        time.sleep(4)
        message=self.driver.find_element_by_class_name(self.first_link_class).text
        return str(message)

class Wiki:

    def __init__(self,driver):

        self.driver=driver
        self.url='https://pt.wikipedia.org/wiki/Wikip%C3%A9dia:P%C3%A1gina_principal'

ff=webdriver.Firefox()
g=Duck(ff)
with open (r"C:\Users\Dell\Documents\documentos\marcas.txt",'r') as f:
    with open (r"C:\Users\Dell\Documents\documentos\links.txt", 'w' ) as fw:
        for line in f :
            g.navigate()
            g.search(line)
            fw.write((line) + g.textconvert()+' \n')


from PyQt5.QtWidgets import QSizePolicy
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib import ticker
import numpy as np

import Meta
import Utils

class MatplotlibWidget(FigureCanvas):
	def __init__(self, parent=None, width=14, height=10, dpi=100):
		fig = Figure(figsize=(width, height), dpi=dpi)
		FigureCanvas.__init__(self, fig)
		self.setParent(parent)
		FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)
		FigureCanvas.updateGeometry(self)

	def updatePlot(self, molec_name, nuMin, nuMax, T, p, cutoff):
		molec_id = Meta.MOLECULE_NAME[molec_name]['molec_id']
		table = self.fetchTable(molec_name, nuMin, nuMax)
		printName = Meta.MOLECULE_NUMBER[table[0][0]]["formula"]
		Utils.getLineStrength(table, T)
		Utils.getPressureShift(table, p)
		_nu, _S = Utils.getColumns(table, ('nu', 's'))
		_nu, _S = Utils.applyCutoff(_nu, _S, cutoff)
		n = len(_nu)
		nu = np.zeros(n * 3)
		S = np.zeros(n * 3)
		std_nu = np.std(nu)
		for i in range(n):
			S[3 * i] = 0
			S[3 * i + 1] = _S[i]
			S[3 * i + 2] = 0
			nu[(3 * i):(3 * i + 3)] = _nu[i]

		# Main Plot
		plot = self.figure.add_subplot(111)
		plot.plot(nu, S)
		plot.axes.set_yscale('log')
		plot.axes.set_ylabel(r'$\chi_i *$Linestrength, [$\frac{cm^{-2}}{atm}$]')
		plot.axes.set_xlabel(r'Wavenumber [cm$^{-1}$]')
		self.figure.gca().yaxis.set_major_formatter(ticker.FormatStrFormatter('%0.e'))
		self.figure.gca().xaxis.set_major_formatter(ticker.FormatStrFormatter('%0.f'))

		self.draw()

	# Scale to x +- 0.1 sigma, y from 0 to max sw + 0.1 sigma
	# ax1.axis([min(nu) - 0.1 * std_nu, max(nu) + 0.1 * std_nu, cutoff, 2 * max(S)])
	# ax1.set_title(r"{0}: {1:.0f} < $\nu$ < {2:.0f}".format(printName, min(nu), max(nu)), y = 1.10)
	def fetchTable(self, molec_name, nuMin, nuMax):
		table = Utils.searchDB_NU(Utils.readFile(molec_name + ".txt"), nuMin, nuMax)
		return table

	def clearPlot(self):
		self.figure.clf()
		self.draw()


from DataEngine.Data import get_pro_stock_basic, get_pro_daily, get_pro_monthly
import prettytable as pt
from time import sleep

def CycleObservation(code='600900.SH',sdate='20100101',edate='20210101',name='万科A'):
    data = get_pro_daily(code, sdate, edate)
    date = list(data['trade_date'])
    date.reverse()
    close_price = list((data['close'] - data['open'])/data['open'])
    close_price.reverse()
    length = len(close_price)
    year_mon = date[0][:6]
    mon = date[0][4:6]
    price = close_price[0]
    month_change = {}
    table = pt.PrettyTable(['name', 'Month', 'Change'])
    for x in range(length):
        if  date[x][:6] != year_mon :
            year_mon = date[x][:6]
            mon = date[x][4:6]
            table.add_row([name, year_mon, round(close_price[x-1] - price,2)])
            price = close_price[x]
            if not month_change.get(mon):
                month_change[mon] = [round(close_price[x-1] - price,2)]
            else:
                month_change[mon].append(round(close_price[x-1] - price,2))
    # print(table)
    ret_m_c = {}
    for x in month_change.keys():
        # print(x,' ---> ', month_change[x], '==>', round(sum(month_change[x])/ len(month_change[x]),4))
        ret_m_c[x] = round(sum(month_change[x])/ len(month_change[x]),4)
    return ret_m_c

if __name__ == '__main__':
    stocks = get_pro_stock_basic()
    codes = [x for x in stocks['ts_code'] if x[0] != 3 and x[:2] != '68']
    names = [x for x in stocks['name']]
    rate = {}
    for x in range(len(codes)):
        if names[x].find('ST') != -1 or x % 100 == 0:
            continue
        # print("\n\n模拟%s 周期观察" % names[x])
        sleep(0.1)
        d = CycleObservation(codes[x], '20150101', '20210110', names[x])
        for x in d.keys():
            if not rate.get(x):
                rate[x] = [d[x]]
            else:
                rate[x].append(d[x])
    for x in rate.keys():
        print(x, '-->', sum(rate[x]))


"""
Пожалуйста, приступайте к этой задаче после того, как вы сделали и получили ревью ко всем остальным задачам
в этом репозитории. Она значительно сложнее.

Есть набор сообщений из чата в следующем формате:

```
messages = [
    {
        "id": "efadb781-9b04-4aad-9afe-e79faef8cffb",
        "sent_at": datetime.datetime(2022, 10, 11, 23, 11, 11, 721),
        "sent_by": 46,  # id пользователя-отправителя
        "reply_for": "7b22ae19-6c58-443e-b138-e22784878581",  # id сообщение, на которое это сообщение является ответом (может быть None)
        "seen_by": [26, 91, 71], # идентификаторы пользователей, которые видели это сообщение
        "text": "А когда ревью будет?",
    }
]
```

1. Вывести айди пользователя, который написал больше всех сообщений.
2. Вывести айди пользователя, на сообщения которого больше всего отвечали.
3. Вывести айди пользователей, сообщения которых видело больше всего уникальных пользователей.
4. Определить, когда в чате больше всего сообщений: утром (до 12 часов), днём (12-18 часов) или вечером (после 18 часов).
5. Вывести идентификаторы сообщений, который стали началом для самых длинных тредов (цепочек ответов).

Весь код стоит разбить на логические части с помощью функций.
"""

messages = [
    {
        "id": "efadb781-9b04-4aad-9afe-e79faef8cffb",
        "sent_at": datetime.datetime(2022, 10, 11, 23, 11, 11, 721),
        "sent_by": 46,  # id пользователя-отправителя
        "reply_for": "7b22ae19-6c58-443e-b138-e22784878581",  # id сообщение, на которое это сообщение является ответом (может быть None)
        "seen_by": [26, 91, 71], # идентификаторы пользователей, которые видели это сообщение
        "text": "А когда ревью будет?",
    }
]
import random
import uuid
import datetime
from typing import List, Dict, Any
import lorem
from collections import Counter

message_counts = Counter(messages ['sent_by'] for message in messages)
# Находим пользователя с максимальным количеством сообщений
most_active_user_id = max(message_counts, key=message_counts.get)

print(f"Пользователь {most_active_user_id} написал больше всех сообщений: {message_counts[most_active_user_id]}")

#Генерирует историю чата с заданным количеством сообщений.
def get_user_with_most_replies(messages: List[Dict[str, Any]]) -> int:
    """
    Возвращает идентификатор пользователя, на сообщения которого больше всего отвечали.

    :param messages: список сообщений
    :return: идентификатор пользователя
    """
    user_reply_count = {}
    for message in messages:
        reply_for = message["reply_for"]
        if reply_for is not None:
            user_id = messages[0]["sent_by"]
            if user_id not in user_reply_count:
                user_reply_count[user_id] = 0
            user_reply_count[user_id] += 1
    return max(user_reply_count, key=user_reply_count.get)

def get_users_with_most_views(messages: List[Dict[str, Any]]) -> List[int]:
    """
    Возвращает список идентификаторов пользователей, сообщения которых видело больше всего уникальных пользователей.

    :param messages: список сообщений
    :return: список идентификаторов пользователей
    """
    user_view_count = {}
    for message in messages:
        seen_by = message["seen_by"]
        for user_id in seen_by:
            if user_id not in user_view_count:
                user_view_count[user_id] = 0
            user_view_count[user_id] += 1
    max_views = max(user_view_count.values())
    return [user_id for user_id, views in user_view_count.items() if views == max_views]

def get_message_count_by_time_of_day(messages: List[Dict[str, Any]]) -> Dict[str, int]:
    """
    Возвращает словарь с количеством сообщений в разное время дня.

    :param messages: список сообщений
    :return: словарь с количеством сообщений в разное время дня
    """
    message_count_by_time = {"утром": 0, "днём": 0, "вечером": 0}
    for message in messages:
        sent_time = message["sent_at"].time()
        if sent_time < datetime.time(12):
            message_count_by_time["утром"] += 1
        elif sent_time < datetime.time(18):
            message_count_by_time["днём"] += 1
        else:
            message_count_by_time["вечером"] += 1
    return message_count_by_time


import requests
from datetime import datetime
import smtplib
import time

MY_LAT = -6.263623 # Your latitude
MY_LONG = 106.891586 -0.127758 # Your longitude
MY_GMAIL=""
MY_PW=""
def cek_posisi_iss():
    response = requests.get(url="http://api.open-notify.org/iss-now.json")
    response.raise_for_status()
    data = response.json()

    iss_latitude = float(data["iss_position"]["latitude"])
    iss_longitude = float(data["iss_position"]["longitude"])
    if MY_LAT-5 <= iss_latitude <= MY_LAT+5 and MY_LONG-5 <= iss_longitude <= MY_LONG+5:
        return True

#Your position is within +5 or -5 degrees of the ISS position.

def cek_waktu():

    parameters = {
        "lat": MY_LAT,
        "lng": MY_LONG,
        "formatted": 0,
    }

    response = requests.get(
        "https://api.sunrise-sunset.org/json", params=parameters)
    response.raise_for_status()
    data = response.json()
    sunrise = int(data["results"]["sunrise"].split("T")[1].split(":")[0])
    sunset = int(data["results"]["sunset"].split("T")[1].split(":")[0])

    time_now = datetime.now().hour
    if time_now >= sunset or time_now <= sunrise:
        return True

while True:
    time.sleep(60)
    if cek_waktu() and cek_posisi_iss():
        koneksi = smtplib.SMTP("smtp.gmail.com")
        koneksi.starttls()
        koneksi.login(MY_GMAIL, MY_PW)
        koneksi.sendmail(
            from_addr=MY_GMAIL,
            to_addrs=MY_PW,
            msg="lihat tuh doatas ada satelite iss "
        )
    else:
        koneksi = smtplib.SMTP("smtp.gmail.com")
        koneksi.starttls()
        koneksi.login(MY_GMAIL, MY_PW)
        koneksi.sendmail(
            from_addr=MY_GMAIL,
            to_addrs=MY_GMAIL,
            msg="tidak ada satelite "
        )

#my_gmail and pw isi sendiri


import cv2
import matplotlib.pyplot as plt

def main():

    imgpath="C:\\Users\\ASH\\Downloads\\Compressed\\standard_test_images\\lena_color_256.tif"
    img=cv2.imread(imgpath,1)

    plt.imshow(img)
    plt.title('Image with Default ColorMap') #giving title to plot
    plt.xticks([])
    plt.yticks([])      #remove x-y scaling
    plt.show()  #show image

    #To convert BGR-formatImageColor(used by cv2) to RGB-formatImageColor(used by matplotlib)
    img =cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

    plt.imshow(img)
    plt.title('Image with Default ColorMap') #giving title to plot
    plt.xticks([])
    plt.yticks([])      #remove x-y scaling
    plt.show()  #show image

if __name__=="__main__":
    main()

COLORSPACES(Correcting color issue bw matplotlib and cv2).py


import os
dir_path  =  os.path.abspath(os.path.join(__file__ ,"../..")) # Moves one level up in the directory

import sys
sys.path.append(dir_path)

import logging
import time
import json
import numpy as np
import pandas as pd
import shutil
import random
from sklearn.utils import shuffle

from src.config import get_config
from src.external_data.google_aerial import fetch_dump_google_aerial_images
from src.semantic_segmentation.overlay_building_bbox import overlay_parcel_on_images, crop_parcel_from_images

def collateData(filesPath, fileType="csv"):
    fileDirList = [os.path.join(filesPath, files) for files in
                   os.listdir(filesPath) if files.endswith('.%s' % fileType)]
    if fileType == "csv":
        rowList = []
        # fileDirList = [files for files in listdir if files.endswith('.csv')]
        for files in fileDirList:
            df = pd.read_csv(files, header=0)
            rowList.append(df)
        return pd.concat(rowList)
    elif fileType == "json":
        dataOUT = {}
        for files in fileDirList:
            jsonFilepath = os.path.join(filesPath, files)
            with open(jsonFilepath, 'r') as fileIN:
                dataOUT = merge(dataOUT, json.load(fileIN))
        return dataOUT

class GetAerial():
    def __init__(self, conf, zoom, state, map_size, batch_size):
        self.conf = conf
        self.zoom = zoom
        self.state = state
        self.map_size = map_size
        self.batch_size = batch_size

        self.inp_img_path = os.path.join(conf['pathDict']['input_image_run_dir'], 'aerial')
        self.stats_path = os.path.join(conf['pathDict']['general_stats_path'], 'aerial', 'aerial_collected_data_stats')

        logging.info('Initiating Aerial Dump ...............................')
        logging.info('Input data path: %s', str(self.inp_img_path))
        logging.info('Stats dump path: %s', str(self.stats_path))

    def parse_dump_aerial(self, land_house_metadata):

        if os.path.exists(self.stats_path):
            if len(os.listdir(self.stats_path)) > 0:
                aerial_stats = collateData(filesPath=self.stats_path, fileType="csv")
                processed_images = aerial_stats.dropna()
                processed_images = processed_images[processed_images['meta_url'] != 'EXCEED']
                logging.info('Number of images already parsed and dumped %s', str(len(aerial_stats)))

                # Delete the seperate batch files batch files
                shutil.rmtree(self.stats_path + '/')
                os.makedirs(self.stats_path)

                # Combine the batchfiles into 1 and save
                processed_images = processed_images[
                    ['pin', 'address', 'city', 'lat', 'lon', 'loc_type', 'indicator', 'meta_url', 'img_url']]
                processed_images.to_csv(os.path.join(self.stats_path, '%s_%s_%s.csv' % (
                    str(time.time()).split('.')[0], str(0), str(len(processed_images) - 1))), index=None)
                land_house_metadata = land_house_metadata[
                    ~land_house_metadata['pin'].isin(np.array(processed_images['pin'], dtype=str))]
        else:
            os.makedirs(self.stats_path)

        land_house_metadata = shuffle(land_house_metadata)
        logging.info('Number of new images to be parsed and dumped: %s', str(len(land_house_metadata)))
        fetch_dump_google_aerial_images(self.conf, land_house_metadata,
                                        self.inp_img_path, self.stats_path,
                                        zoom=self.zoom, state=self.state,
                                        map_size=self.map_size,
                                        batch_size=self.batch_size, get_stats=True)

        return 'COMPLETE'

class GetOverlaid():
    '''
        Note : In the parse_dump_overlaid function we hard code the selection process i.e the image should be
        roof-top, ans should be from Chicago because we have property shape files only for Chicago region
        Since overlaid are created using Aerial Images we take reference of that directory

        * Now that we have Google Aerial Images metadata, we perform the below operation to do some supposedly "bad
        data" removal
            * A image should have a valid address_line1 and city. The address should not start with '0 0 GROVE AVE',
            '0 SUMMIT ST', '0 VACANT PROPERTY'
            * The location_type should not be "RANGE_INTERPOLATED"
            * The Lat and Lon should have a 4 or more than 4 decimal precision.
    '''

    def __init__(self, conf):
        self.conf = conf
        self.overlaid_image_path = os.path.join(conf['pathDict']['input_image_run_dir'], 'overlaid')
        self.aerial_image_path = os.path.join(conf['pathDict']['input_image_run_dir'], 'aerial')
        self.stats_path = os.path.join(conf['pathDict']['general_stats_path'], 'aerial', 'aerial_collected_data_stats')

        if not os.path.exists(self.stats_path) or not os.path.exists(self.aerial_image_path):
            raise ValueError("Is seems you haven't, dumped the Aerial Images, fetching Aerial image is a prerequisite "
                             "to creating overlaid images ", )

        logging.info('Initiating Aerial Overlaid ...............................')
        logging.info('Input data path: %s', str(self.aerial_image_path))
        logging.info('Output data path: %s', str(self.overlaid_image_path))

    def parse_dump_overlaid(self):
        aerial_stats_data = collateData(self.stats_path)
        # print('Number of Images to be processed = ', len(aerial_stats_data))

        data_to_model = aerial_stats_data[(aerial_stats_data['loc_type'] != 'RANGE_INTERPOLATED') & (
            aerial_stats_data['city'].str.lower().str.strip().str.match('chicago')) & (~aerial_stats_data[
            'address'].str.lower().str.strip().str.match('0'))]
        # print('Shape: Images for Overlaying: ', data_to_model.shape)
        overlay_parcel_on_images(self.conf, data_to_model, self.aerial_image_path, self.overlaid_image_path,
                                 zoom=20, map_size=[400, 400])

        return 'COMPLETE'

class GetAerialCropped():
    '''
        Note : In the parse_dump_overlaid function we hard code the selection process i.e the image should be
        roof-top, ans should be from Chicago because we have property shape files only for Chicago region
        Since overlaid are created using Aerial Images we take reference of that directory

        * Now that we have Google Aerial Images metadata, we perform the below operation to do some supposedly "bad
        data" removal
            * A image should have a valid address_line1 and city. The address should not start with '0 0 GROVE AVE',
            '0 SUMMIT ST', '0 VACANT PROPERTY'
            * The location_type should not be "RANGE_INTERPOLATED"
            * The Lat and Lon should have a 4 or more than 4 decimal precision.
    '''

    def __init__(self, conf):
        self.conf = conf
        self.aerial_cropped_img_path = os.path.join(conf['pathDict']['input_image_run_dir'], 'aerial_cropped')
        self.aerial_image_path = os.path.join(conf['pathDict']['input_image_run_dir'], 'aerial')

        self.stats_path = os.path.join(conf['pathDict']['general_stats_path'], 'aerial', 'aerial_collected_data_stats')

        if not os.path.exists(self.stats_path) or not os.path.exists(self.aerial_image_path):
            raise ValueError("Is seems you haven't, dumped the Aerial Images, fetching Aerial image is a prerequite "
                             "to creating overlaid images ", )

        logging.info('Initiating Aerial Crop ...............................')
        logging.info('Input data path: %s', str(self.aerial_image_path))
        logging.info('Output data path: %s', str(self.aerial_cropped_img_path))

    def parse_dump_aerial_cropped(self, condition_apply=False):
        aerial_stats_data = collateData(self.stats_path)
        # print('Number of Images to be processed = ', len(aerial_stats_data))

        if condition_apply:
            logging.info('Apply Condition: RANGE_INTERPOLATED and CHICAGO')
            data_to_model = aerial_stats_data[(aerial_stats_data['loc_type'] != 'RANGE_INTERPOLATED') & (
                aerial_stats_data['city'].str.lower().str.strip().str.match('chicago')) & (~aerial_stats_data[
                'address'].str.lower().str.strip().str.match('0'))]
        else:
            data_to_model = aerial_stats_data[~aerial_stats_data['address'].str.lower().str.strip().str.match('0')]
        # print('Shape: Images for Overlaying: ', data_to_model.shape)
        crop_parcel_from_images(self.conf, data_to_model, self.aerial_image_path, self.aerial_cropped_img_path,
                                zoom=20, map_size=[400, 400])
        return 'COMPLETE'

def data_selection_cond(conf, cond_dict, your_csv_file_path):
    metadata = pd.read_csv(your_csv_file_path)
    metadata.columns = ['row_id', 'removed', 'property_id', 'state', 'county_name', 'pin',
                        'address_line1', 'address_line2', 'address_city', 'address_zip',
                        'zoning', 'improvement_level', 'type', 'exterior',
                        'last_reviewed_timestamp', 'gone_timestamp', 'indicator',
                        'assessor_photo']
    metadata['state'] = metadata['state'].astype('str')
    metadata['county_name'] = metadata['county_name'].astype('str')
    metadata['pin'] = metadata['pin'].astype('str')
    metadata['address_line1'] = metadata['address_line1'].astype('str')
    metadata['address_line2'] = metadata['address_line2'].astype('str')
    metadata['address_city'] = metadata['address_city'].astype('str')
    metadata['address_zip'] = metadata['address_zip'].astype('str')
    metadata['zoning'] = metadata['zoning'].astype('str')
    metadata['improvement_level'] = metadata['improvement_level'].astype('str')
    metadata['type'] = metadata['type'].astype('str')
    metadata['exterior'] = metadata['exterior'].astype('str')
    metadata['last_reviewed_timestamp'] = pd.to_datetime(metadata['last_reviewed_timestamp'])  # .astype('str')
    metadata['gone_timestamp'] = pd.to_datetime(metadata['gone_timestamp'])  # .astype('str')
    metadata['indicator'] = metadata['indicator'].astype('str')
    metadata['assessor_photo'] = metadata['assessor_photo'].astype('str')

    # Remove the Test Dat from Metadata
    metadata = metadata[metadata['removed'] == 0]
    print ('Shape: Metadata table', str(metadata.shape))

    property_metadata = metadata
    if cond_dict['last_reviewed_ts']:
        property_metadata = property_metadata[property_metadata['last_reviewed_timestamp'] != '']
        property_metadata['last_reviewed_timestamp'] = pd.to_datetime(
                property_metadata['last_reviewed_timestamp'])
        print('Data shape  = %s' % (str(property_metadata.shape)))
        if cond_dict['from_year'] and cond_dict['to_year']:
            print ('Applying conditions: from_year %s - to_year %s'%(str(cond_dict['from_year']), str(cond_dict['from_year'])))
            property_metadata = property_metadata[
                ((property_metadata['last_reviewed_timestamp'].dt.year >= cond_dict['from_year']) &
                 (property_metadata['last_reviewed_timestamp'].dt.year < cond_dict['to_year']))]
            print('Data shape  = %s' % (str(property_metadata.shape)))

        if cond_dict['from_month'] and cond_dict['to_month']:
            print('Applying conditions: from_month %s - to_month %s' % (
            str(cond_dict['from_month']), str(cond_dict['from_month'])))
            property_metadata = property_metadata[
            ((property_metadata['last_reviewed_timestamp'].dt.month >= cond_dict['from_month']) &
            (property_metadata['last_reviewed_timestamp'].dt.month < cond_dict['to_month']))]
            print('Data shape  = %s' % (str(property_metadata.shape)))

    if cond_dict['which_city']:
        print('Applying conditions: city: %s' % (str(cond_dict['which_city'])))
        property_metadata = property_metadata[
            (property_metadata['address_city'].str.lower().str.strip().str.match(cond_dict['which_city']))]
        print('Data shape  = %s' % (str(property_metadata.shape)))

    property_metadata = property_metadata[
        (property_metadata['address_line1'] != 'nan') &
        (property_metadata['indicator'].isin(["Likely House", "Likely Land"]))]

    if cond_dict['use_improvement_lvl']:
        print('Applying conditions: improvement_lvl: True')
        land_data = property_metadata[(property_metadata['indicator'] == 'Likely Land') & (property_metadata['improvement_level'] =='Land')]

        house_data = property_metadata[(property_metadata['indicator'] == 'Likely House') & (property_metadata['improvement_level'] != 'Land')]
        print('Data shape land = %s, house = %s' % (str(land_data.shape), str(house_data.shape)))
    else:
        land_data = property_metadata[(property_metadata['indicator'] == 'Likely Land')]

        house_data = property_metadata[(property_metadata['indicator'] == 'Likely House')]

    if cond_dict['max_num_records']:
        random.seed(481)
        n = cond_dict['max_num_records']
        print('Applying conditions: max_num_records: %s'%(n))
        land_data = land_data.reset_index().drop('index', axis=1)
        house_data = house_data.reset_index().drop('index', axis=1)

        if len(land_data) >= n//2:
            lindex = np.array(random.sample(list(range(len(land_data))), n // 2))
            land_data = land_data.ix[lindex]
        if len(house_data) >= n//2:
            rindex = np.array(random.sample(list(range(len(house_data))), n // 2))
            house_data = house_data.ix[rindex]

    print('Shape: Land Property table %s'%(str(land_data.shape)))
    print('Shape: House Property table %s'%(str(house_data.shape)))

    filtered_data = pd.concat([land_data, house_data]).reset_index().drop('index', axis=1)

    filtered_data.to_csv(os.path.join(conf['pathDict']['csv_path'], 'input_data.csv'), index=None)

    return 'COMPLETE'

# cond_dict = dict(last_reviewed_ts=True,
#                  from_year=2015, to_year=2015,
#                  from_month=5, to_month=6,
#                  which_city='chicago',
#                  use_improvement_lvl = True,
#                  max_num_records=200)
#
# conf = get_config(which_run='new_new', img_type='aerial_cropped')
# a  = data_selection_cond(conf, cond_dict)
# print (a)

def create_csv_file_for_input(**kwargs):
    inp_params = kwargs['params']

    if 'input_csv_path' not in inp_params.keys():
        raise ValueError('You should provide the path to input csv file')

    if 'which_run' not in inp_params.keys():
        raise ValueError('You should provide the name of RUN')

    if 'img_type' not in inp_params.keys():
        raise ValueError('You should provide a valid image type to create batches')

    if 'cond_dict' not in inp_params.keys():
        raise ValueError('You should provide the conditions to filter data for testing')

    conf = get_config(which_run=inp_params['which_run'], img_type=inp_params['img_type'])

    status = data_selection_cond(conf, inp_params['cond_dict'], inp_params['input_csv_path'])

    return status

def dump_aerial(**kwargs):
    inp_params = kwargs['params']

    if 'which_run' not in inp_params.keys():
        raise ValueError('You should provide the name of RUN')

    if 'img_type' not in inp_params.keys():
        raise ValueError('You should provide a valid image type to create batches')

    conf = get_config(which_run=inp_params['which_run'], img_type=inp_params['img_type'])

    land_house_data = pd.read_csv(os.path.join(conf['pathDict']['csv_path'], 'input_data.csv'))

    status = GetAerial(conf, zoom=20, state='IL', map_size = '400x400', batch_size=100).parse_dump_aerial(
            land_house_data)
    return status

def dump_aerial_cropped(**kwargs):
    inp_params = kwargs['params']

    if 'which_run' not in inp_params.keys():
        raise ValueError('You should provide the name of RUN')

    if 'img_type' not in inp_params.keys():
        raise ValueError('You should provide a valid image type to create batches')

    conf = get_config(which_run=inp_params['which_run'], img_type=inp_params['img_type'])
    obj_cropped = GetAerialCropped(conf)
    status = obj_cropped.parse_dump_aerial_cropped(condition_apply=True)
    return status

def dump_overlaid(**kwargs):
    inp_params = kwargs['params']

    if 'which_run' not in inp_params.keys():
        raise ValueError('You should provide the name of RUN')

    if 'img_type' not in inp_params.keys():
        raise ValueError('You should provide a valid image type to create batches')

    conf = get_config(which_run=inp_params['which_run'], img_type=inp_params['img_type'])
    obj_overlaid = GetOverlaid(conf)
    status = obj_overlaid.parse_dump_overlaid()
    return status

#
#
#
# def data_selection_cond1(conf):
#     parent_path = conf['pathDict']['parent_path']
#     meta_data_path = os.path.join(parent_path, "house_metadata_nw.csv")
#     metadata = pd.read_csv(meta_data_path)
#     metadata.columns = ['row_id', 'removed', 'property_id', 'state', 'county_name', 'pin',
#                         'address_line1', 'address_line2', 'address_city', 'address_zip',
#                         'zoning', 'improvement_level', 'type', 'exterior',
#                         'last_reviewed_timestamp', 'gone_timestamp', 'indicator',
#                         'assessor_photo']
#     metadata['state'] = metadata['state'].astype('str')
#     metadata['county_name'] = metadata['county_name'].astype('str')
#     metadata['pin'] = metadata['pin'].astype('str')
#     metadata['address_line1'] = metadata['address_line1'].astype('str')
#     metadata['address_line2'] = metadata['address_line2'].astype('str')
#     metadata['address_city'] = metadata['address_city'].astype('str')
#     metadata['address_zip'] = metadata['address_zip'].astype('str')
#     metadata['zoning'] = metadata['zoning'].astype('str')
#     metadata['improvement_level'] = metadata['improvement_level'].astype('str')
#     metadata['type'] = metadata['type'].astype('str')
#     metadata['exterior'] = metadata['exterior'].astype('str')
#     metadata['last_reviewed_timestamp'] = pd.to_datetime(metadata['last_reviewed_timestamp'])  # .astype('str')
#     metadata['gone_timestamp'] = pd.to_datetime(metadata['gone_timestamp'])  # .astype('str')
#     metadata['indicator'] = metadata['indicator'].astype('str')
#     metadata['assessor_photo'] = metadata['assessor_photo'].astype('str')
#
#     # Remove the Test Dat from Metadata
#     metadata = metadata[metadata['removed'] == 0]
#     logging.info('Shape: Metadata table %s', str(metadata.shape))
#
#     property_metadata = metadata[metadata['last_reviewed_timestamp'] != '']
#     property_metadata['last_reviewed_timestamp'] = pd.to_datetime(
#             property_metadata['last_reviewed_timestamp'])
#     property_metadata = property_metadata[
#         ((property_metadata['last_reviewed_timestamp'].dt.year == 2015) &
#          (property_metadata['last_reviewed_timestamp'].dt.month >= 5) &
#          (property_metadata['last_reviewed_timestamp'].dt.month < 7) &
#          (property_metadata['address_city'].str.lower().str.strip().str.match('chicago')) &
#          (property_metadata['address_line1'] != 'nan') &
#          (property_metadata['assessor_photo'] != 'nan') &
#          (property_metadata['indicator'].isin(["Likely House", "Likely Land"])
#           ))
#     ]
#
#     land_data = property_metadata[
#         (property_metadata['indicator'] == 'Likely Land') & (property_metadata['improvement_level'] ==
#                                                              'Land')]
#     logging.info('Shape: Land Property table %s', str(land_data.shape))
#     house_data = property_metadata[
#         (property_metadata['indicator'] == 'Likely House') & (property_metadata['improvement_level'] != 'Land')]
#     logging.info('Shape: House Property table %s', house_data.shape)
#
#     return pd.concat([land_data, house_data])

#
# from src.config import get_config
# conf = get_config('jordan', 'aerial_cropped')
# out = data_selection_cond1(conf)
# print (out)