#Ahtisham Ali Jan
#2023-10-0251
#CS331

# search.py
# ---------
# Licensing Information:  You are free to use or extend these projects for
# educational purposes provided that (1) you do not distribute or publish
# solutions, (2) you retain this notice, and (3) you provide clear
# attribution to UC Berkeley, including a link to http://ai.berkeley.edu.
#
# Attribution Information: The Pacman AI projects were developed at UC Berkeley.
# The core projects and autograders were primarily created by John DeNero
# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu).
# Student side autograding was added by Brad Miller, Nick Hay, and
# Pieter Abbeel (pabbeel@cs.berkeley.edu).

"""
In search.py, you will implement generic search algorithms which are called by
Pacman agents (in searchAgents.py).
"""

import util

class SearchProblem:
	"""
	This class outlines the structure of a search problem, but doesn't implement
	any of the methods (in object-oriented terminology: an abstract class).

	You do not need to change anything in this class, ever.
	"""

	def getStartState(self):
		"""
		Returns the start state for the search problem.
		"""
		util.raiseNotDefined()

	def isGoalState(self, state):
		"""
		  state: Search state

		Returns True if and only if the state is a valid goal state.
		"""
		util.raiseNotDefined()

	def getSuccessors(self, state):
		"""
		  state: Search state

		For a given state, this should return a list of triples, (successor,
		action, stepCost), where 'successor' is a successor to the current
		state, 'action' is the action required to get there, and 'stepCost' is
		the incremental cost of expanding to that successor.
		"""
		util.raiseNotDefined()

	def getCostOfActions(self, actions):
		"""
		 actions: A list of actions to take

		This method returns the total cost of a particular sequence of actions.
		The sequence must be composed of legal moves.
		"""
		util.raiseNotDefined()

def tinyMazeSearch(problem):
	"""
	Returns a sequence of moves that solves tinyMaze.  For any other maze, the
	sequence of moves will be incorrect, so only use this for tinyMaze.
	"""
	from game import Directions
	s = Directions.SOUTH
	w = Directions.WEST
	return  [s, s, w, s, w, w, s, w]

def depthFirstSearch(problem):
	"""
	Search the deepest nodes in the search tree first.

	Your search algorithm needs to return a list of actions that reaches the
	goal. Make sure to implement a graph search algorithm.

	To get started, you might want to try some of these simple commands to
	understand the search problem that is being passed in:
		"""
	# print("Start:", problem.getStartState())
	# print("Is the start a goal?", problem.isGoalState(problem.getStartState()))
	# print("Start's successors:", problem.getSuccessors(problem.getStartState()))

	closed = set()
	fringe = util.Stack()
	fringe.push((problem.getStartState(),[]))

	while not fringe.isEmpty():
		state, nodes = fringe.pop()
		if problem.isGoalState(state):
			return nodes
		else:
			if state not in closed:
				closed.add(state)
				childNodes = problem.getSuccessors(state)
				fringe = getChildNodes(fringe,childNodes,closed,nodes)
	return []

class _RecursiveDepthFirstSearch(object):
	'''
		=> Output of 'recursive' dfs should match that of 'iterative' dfs you implemented
		above.
		Key Point: Remember in tutorial you were asked to expand the left-most child
		first for dfs and bfs for consistency. If you expanded the right-most
		first, dfs/bfs would be correct in principle but may not return the same
		path.

		=> Useful Hint: self.problem.getSuccessors(node) will return children of
		a node in a certain "sequence", say (A->B->C), If your 'recursive' dfs traversal
		is different from 'iterative' traversal, try reversing the sequence.

	'''
	def __init__(self, problem):
		" Do not change this. "
		# You'll save the actions that recursive dfs found in self.actions.
		self.actions = []
		# Use self.explored to keep track of explored nodes.
		self.explored = set()
		self.problem = problem

	def RecursiveDepthFirstSearchHelper(self, node):
		'''
		args: start node
		outputs: bool => True if path found else Fasle.
		'''
		if self.problem.isGoalState(node):
			return True
		self.explored.add(node)
		childNodes = self.problem.getSuccessors(node)
		return helperRecursive(self,childNodes)

def RecursiveDepthFirstSearch(problem):
	" You need not change this function. "
	# All your code should be in member function 'RecursiveDepthFirstSearchHelper' of
	# class '_RecursiveDepthFirstSearch'."

	node = problem.getStartState()
	rdfs = _RecursiveDepthFirstSearch(problem)
	path_found = rdfs.RecursiveDepthFirstSearchHelper(node)
	return list(reversed(rdfs.actions)) # Actions your recursive calls return are in opposite order.
# ________________________________________________________________

def depthLimitedSearch(problem, limit = 209):

	"""
	Search the deepest nodes in the search tree first as long as the
	nodes are not not deeper than 'limit'.

	For medium maze, pacman should find food for limit less than 130.
	If your solution needs 'limit' more than 130, it's bogus.
	Specifically, for:
	'python pacman.py -l mediumMaze -p SearchAgent -a fn=dls', and limit=130
	pacman should work normally.

	Your search algorithm needs to return a list of actions that reaches the
	goal. Make sure to implement a graph search algorithm.
	Autograder cannot test this function.

	Hints: You may need to store additional information in your frontier(queue).

		"""
	closed = set()
	fringe = util.Stack()
	depth= 0
	fringe.push((problem.getStartState(),[],depth))

	while not fringe.isEmpty():
		state, nodes, depth = fringe.pop()
		if problem.isGoalState(state):
			return nodes
		else:
			if state not in closed:
				closed.add(state)
				childNodes = problem.getSuccessors(state)
				if childNodes and depth <= limit:
					fringe = getChildNodes(fringe,childNodes,closed,nodes,depth)
	return []

class _RecursiveDepthLimitedSearch(object):
	'''
		=> Output of 'recursive' dfs should match that of 'iterative' dfs you implemented
		above.
		Key Point: Remember in tutorial you were asked to expand the left-most child
		first for dfs and bfs for consistency. If you expanded the right-most
		first, dfs/bfs would be correct in principle but may not return the same
		path.

		=> Useful Hint: self.problem.getSuccessors(node) will return children of
		a node in a certain "sequence", say (A->B->C), If your 'recursive' dfs traversal
		is different from 'iterative' traversal, try reversing the sequence.

	'''
	def __init__(self, problem):
		" Do not change this. "
		# You'll save the actions that recursive dfs found in self.actions.
		self.actions = []
		# Use self.explored to keep track of explored nodes.
		self.explored = set()
		self.problem = problem
		self.current_depth = 0
		self.depth_limit = 204 # For medium maze, You should find solution for depth_limit not more than 204.

	def RecursiveDepthLimitedSearchHelper(self, node):

		if self.problem.isGoalState(node):
			return True
		self.explored.add(node)
		childNodes = self.problem.getSuccessors(node)
		if childNodes and self.current_depth <= self.depth_limit:
			return helperRecursive(self,childNodes,1)
		else:
			return False

def RecursiveDepthLimitedSearch(problem):
	"You need not change this function. All your code in member function RecursiveDepthLimitedSearchHelper"
	node = problem.getStartState()
	rdfs = _RecursiveDepthLimitedSearch(problem)
	path_found = rdfs.RecursiveDepthLimitedSearchHelper(node)
	return list(reversed(rdfs.actions)) # Actions your recursive calls return are in opposite order.
# ________________________________________________________________

def breadthFirstSearch(problem):

	closed = set()
	fringe = util.Queue()
	fringe.push((problem.getStartState(),[]))

	while not fringe.isEmpty():
		state, nodes = fringe.pop()
		if problem.isGoalState(state):
			return nodes
		else:
			if state not in closed:
				closed.add(state)
				childNodes = problem.getSuccessors(state)
				fringe = getChildNodes(fringe,childNodes,closed,nodes)
	return []

def uniformCostSearch(problem):
	copy = list()
	closed = set()
	fringe = util.PriorityQueue()
	fringe.push((problem.getStartState(),[]),0)
	copy.append(problem.getStartState())

	while not fringe.isEmpty():
		state, priority = fringe.pop()
		copy.remove(state[0])
		if problem.isGoalState(state[0]):
			return state[1]

		closed.add(state[0])
		childNodes = problem.getSuccessors(state[0])
		fringe = helperCost(childNodes,fringe,state,priority,closed,copy)
	return []
def nullHeuristic(state, problem=None):
	"""
	A heuristic function estimates the cost from the current state to the nearest
	goal in the provided SearchProblem.  This heuristic is trivial.
	"""
	return 0

def aStarSearch(problem, heuristic=nullHeuristic):
	'''
	Pay clos attention to util.py- specifically, args you pass to member functions.

	Key Point: If a node is already present in the queue with higher path cost
	(or higher priority), you'll update its cost (or priority)
	(Similar to pseudocode in figure 3.14 of your textbook.).
	Be careful, autograder cannot catch this bug.

	'''

# Abbreviations
bfs = breadthFirstSearch
dfs = depthFirstSearch
rdfs = RecursiveDepthFirstSearch
dls = depthLimitedSearch
rdls = RecursiveDepthLimitedSearch
astar = aStarSearch
ucs = uniformCostSearch

#Added Helper Functions
def getChildNodes(stack_queue,childNodes,closed,nodes, depth = -1):
	for node in childNodes:
		if node[0] not in closed:
			path = list()
			for i in nodes:
				path.append(i)
			fringe = path + [node[1]]
			if depth == -1:
				stack_queue.push((node[0],fringe))
			else:
				stack_queue.push((node[0],fringe,depth+1))
	return stack_queue

def helperRecursive(self,childNodes,depth = 0):
	if depth == 1:
		self.current_depth = self.current_depth +1
	childNodes.reverse()
	for child in childNodes:
		if child[0] not in self.explored:
			if depth == 1:
				check = self.RecursiveDepthLimitedSearchHelper(child[0])
			else:
				check = self.RecursiveDepthFirstSearchHelper(child[0])
			if check == True:
				self.actions.append(child[1])
				return True
	return False

def helperCost(childNodes,priorityQueue,state,priority,closed,copy):
	for child in childNodes:
		child_node,child_path,child_cost = child[0],child[1],priority + child[2]
		path = list()
		for i in state[1]:
			path.append(i)
		info = (child_node,path)
		path.append(child_path)
		if priorityQueue.item_present_with_higher_priority(info, child_cost) != None:
			i, c = priorityQueue.item_present_with_higher_priority(info, child_cost)
			priorityQueue.Update_priority(info,child_cost, i, c)
		elif child_node not in closed and child_node not in copy:
			priorityQueue.push(info, child_cost)
			copy.append(child_node)
	return priorityQueue


import numpy as np
from trend_prediction import predict
from PIL import Image
from adv2_pairwise_trend import get_trend
from matching_adjustment import find_n_neighbors as fn
from image_utils import create_mat as cm, create_mat_contour as cmc
from trend_analysis_UI import TrendUI
from trend_analysis import find_paths_indices, find_paths_pts

bef_path = './trend_analysis/3.png'
aft_path = './trend_analysis/4.png'
images = [ Image.open(bef_path), Image.open(aft_path)]
thumbnail = (100, 200)
for image in images:
	image.thumbnail(thumbnail)

mat_images = np.array([cmc(img, GB=0.8)  for img in images])

width, height = images[0].size

k = 300

num_images = len(images)
matched_indexes_total = []
retain_points = None
# identify pair-wise trends
for index, mat_img_bef in enumerate(mat_images):
	if (index == len(mat_images) - 1):
		break
	mat_img_aft = mat_images[index + 1]

	print (num_images - index - 1," remaining")

	matched_indexes, retain_points = get_trend(mat_img_bef, mat_img_aft, width, k, retain_points)

	matched_indexes_total.append(matched_indexes)

print("find paths...")
paths = find_paths_indices(matched_indexes_total)

print ("find pts along paths...")

paths_pts = find_paths_pts(paths, mat_images)

#print(paths_pts)

ini_image = Image.new('RGB', (width, height))
#ini_image = Image.open(bef_path)
ui = TrendUI(paths_pts, [], ini_image)


from django.conf.urls import url, include
from rest_framework.routers import DefaultRouter
from meal_manager.api.views import ProductViewSet, ProductTypeViewSet

__author__ = 'Wojciech Rydel <rydel.wojciech@gmail.com>'

router = DefaultRouter()
router.register(r'^products', ProductViewSet, base_name='product')
router.register(r'^types', ProductTypeViewSet, base_name='type')

urlpatterns = [
    url(r'^', include(router.urls, namespace='meal_manager')),
]


from datetime import date
from typing import Any, Callable, Dict, List, Optional, Union

from django.contrib.auth.models import User
from django.contrib.sessions.backends.base import SessionBase
from django.core.handlers.base import BaseHandler
from django.core.handlers.wsgi import WSGIRequest
from django.dispatch.dispatcher import Signal
from django.http.request import HttpRequest, QueryDict
from django.http.response import (HttpResponse, HttpResponseBase,
                                  HttpResponseRedirect)
from django.template.base import Template
from django.template.context import Context
from django.test.utils import ContextList

class RedirectCycleError(Exception):
    last_response: django.http.response.HttpResponseRedirect = ...
    redirect_chain: List[Tuple[str, int]] = ...
    def __init__(
        self, message: str, last_response: HttpResponseRedirect
    ) -> None: ...

class FakePayload:
    read_started: bool = ...
    def __init__(self, content: Optional[Union[bytes, str]] = ...) -> None: ...
    def __len__(self) -> int: ...
    def read(self, num_bytes: int = ...) -> bytes: ...
    def write(self, content: Union[bytes, str]) -> None: ...

class ClientHandler(BaseHandler):
    enforce_csrf_checks: bool = ...
    def __init__(
        self, enforce_csrf_checks: bool = ..., *args: Any, **kwargs: Any
    ) -> None: ...
    def __call__(self, environ: Dict[str, Any]) -> HttpResponseBase: ...

def encode_multipart(boundary: str, data: Dict[str, Any]) -> bytes: ...
def encode_file(boundary: str, key: str, file: Any) -> List[bytes]: ...

class RequestFactory:
    json_encoder: Type[django.core.serializers.json.DjangoJSONEncoder] = ...
    defaults: Dict[str, str] = ...
    cookies: http.cookies.SimpleCookie = ...
    errors: _io.BytesIO = ...
    def __init__(self, *, json_encoder: Any = ..., **defaults: Any) -> None: ...
    def request(self, **request: Any) -> WSGIRequest: ...
    def get(
        self,
        path: str,
        data: Optional[Union[Dict[str, date], QueryDict, str]] = ...,
        secure: bool = ...,
        **extra: Any
    ) -> Union[WSGIRequest, HttpResponseBase]: ...
    def post(
        self,
        path: str,
        data: Any = ...,
        content_type: str = ...,
        secure: bool = ...,
        **extra: Any
    ) -> Union[WSGIRequest, HttpResponseBase]: ...
    def head(
        self,
        path: str,
        data: Optional[Union[Dict[str, str], str]] = ...,
        secure: bool = ...,
        **extra: Any
    ) -> Union[WSGIRequest, HttpResponse]: ...
    def trace(
        self, path: str, secure: bool = ..., **extra: Any
    ) -> Union[WSGIRequest, HttpResponse]: ...
    def options(
        self,
        path: str,
        data: Union[Dict[str, str], str] = ...,
        content_type: str = ...,
        secure: bool = ...,
        **extra: Any
    ) -> Union[WSGIRequest, HttpResponse]: ...
    def put(
        self,
        path: str,
        data: Union[Dict[str, int], Dict[str, str], bytes, str] = ...,
        content_type: str = ...,
        secure: bool = ...,
        **extra: Any
    ) -> Union[WSGIRequest, HttpResponse]: ...
    def patch(
        self,
        path: str,
        data: Union[Dict[str, int], Dict[str, str], str] = ...,
        content_type: str = ...,
        secure: bool = ...,
        **extra: Any
    ) -> Union[WSGIRequest, HttpResponse]: ...
    def delete(
        self,
        path: str,
        data: Union[Dict[str, int], Dict[str, str], str] = ...,
        content_type: str = ...,
        secure: bool = ...,
        **extra: Any
    ) -> Union[WSGIRequest, HttpResponse]: ...
    def generic(
        self,
        method: str,
        path: str,
        data: Union[Dict[str, str], bytes, str] = ...,
        content_type: Optional[str] = ...,
        secure: bool = ...,
        **extra: Any
    ) -> Union[WSGIRequest, HttpResponseBase]: ...

class Client(RequestFactory):
    defaults: Dict[str, str]
    errors: _io.BytesIO
    json_encoder: Union[
        Type[django.core.serializers.json.DjangoJSONEncoder],
        unittest.mock.MagicMock,
    ]
    handler: django.test.client.ClientHandler = ...
    exc_info: None = ...
    def __init__(
        self, enforce_csrf_checks: bool = ..., **defaults: Any
    ) -> None: ...
    def store_exc_info(self, **kwargs: Any) -> None: ...
    @property
    def session(self) -> SessionBase: ...
    def request(self, **request: Any) -> Any: ...
    def get(
        self,
        path: str,
        data: Optional[Union[Dict[str, Union[int, str]], QueryDict, str]] = ...,
        follow: bool = ...,
        secure: bool = ...,
        **extra: Any
    ) -> HttpResponseBase: ...
    def post(
        self,
        path: str,
        data: Any = ...,
        content_type: str = ...,
        follow: bool = ...,
        secure: bool = ...,
        **extra: Any
    ) -> HttpResponseBase: ...
    def head(
        self,
        path: str,
        data: Optional[Union[Dict[str, str], str]] = ...,
        follow: bool = ...,
        secure: bool = ...,
        **extra: Any
    ) -> HttpResponse: ...
    def options(
        self,
        path: str,
        data: Union[Dict[str, str], str] = ...,
        content_type: str = ...,
        follow: bool = ...,
        secure: bool = ...,
        **extra: Any
    ) -> HttpResponse: ...
    def put(
        self,
        path: str,
        data: Union[Dict[str, int], Dict[str, str], bytes, str] = ...,
        content_type: str = ...,
        follow: bool = ...,
        secure: bool = ...,
        **extra: Any
    ) -> HttpResponse: ...
    def patch(
        self,
        path: str,
        data: Union[Dict[str, int], Dict[str, str], str] = ...,
        content_type: str = ...,
        follow: bool = ...,
        secure: bool = ...,
        **extra: Any
    ) -> HttpResponse: ...
    def delete(
        self,
        path: str,
        data: Union[Dict[str, int], Dict[str, str], str] = ...,
        content_type: str = ...,
        follow: bool = ...,
        secure: bool = ...,
        **extra: Any
    ) -> HttpResponse: ...
    def trace(
        self,
        path: str,
        data: Union[Dict[str, str], str] = ...,
        follow: bool = ...,
        secure: bool = ...,
        **extra: Any
    ) -> HttpResponse: ...
    def login(self, **credentials: Any) -> bool: ...
    def force_login(self, user: User, backend: Optional[str] = ...) -> None: ...
    cookies: http.cookies.SimpleCookie = ...
    def logout(self) -> None: ...


"""A video player class."""

from .video_library import VideoLibrary
from .video_playlist import Playlist
import random
import re

class VideoPlayer:
    """A class used to represent a Video Player."""

    def __init__(self):
        self._video_library = VideoLibrary()
        self._video_playing = None
        self.video_paused = False
        self._playlists = list()

    def get_video_library(self):
        return self._video_library

    def number_of_videos(self):
        num_videos = len(self._video_library.get_all_videos())
        print(f"{num_videos} videos in the library")

    def show_all_videos(self):
        """Returns all videos."""

        print("show_all_videos needs implementation")
        print("Here's a list of all available videos: ")
        videos = self._video_library.get_all_videos()
        for vid in sorted(videos, key=lambda v: v.title[0]):
            # Part 4 Flag_Video task: add flag when showing flagged videos
            print('\t{0}{1}'.format(vid, " - FLAGGED (reason: {0})".format(vid.flag) if vid.flag else ""))
            # print("show_all_videos needs implementation")

    def play_video(self, video_id):
        """Plays the respective video.

        Args:
            video_id: The video_id to be played.
        """
        print("play_video needs implementation")
        print("play_video needs implementation")
        # print("play_video needs implementation")
        # 1. Search video by id
        video_result = self._video_library.get_video(video_id)
        if video_result is None:
            print("Cannot play video: Video does not exist")
            return
        # 2. Part 4 FLAG_VIDEO task: Check if the video is flagged
        if video_result.flag:
            print("Cannot play video: Video is currently flagged (reason: {0})".format(video_result.flag))
            return
        # 3. Check and Try stop playing video
        if self._video_playing is not None:
            self.stop_video()
        # 4. Play video
        print("Playing video: {0}".format(video_result.title))
        self._video_playing = video_result
        self._video_paused = False

    def stop_video(self):
        """Stops the current video."""

        print("stop_video needs implementation")
        # 1. Check if any video is playing
        if self._video_playing is None:
            print("Cannot stop video: No video is currently playing")
            return
        # 2. Stop playing video
        print("Stopping video: {0}".format(self._video_playing.title))
        self._video_playing = None
        self._video_paused = False

    def play_random_video(self):
        """Plays a random video from the video library."""

        print("play_random_video needs implementation")
        videos = self._video_library.get_all_videos()
        # 1. Part 4 FLAG_VIDEO task: filter all flagged video(s) out
        videos = list(filter(lambda vid: not vid.flag, videos))
        # 2. Check if any videos available
        if len(videos) == 0:
            print("No videos available")
            return
        # 3. shuffle and play first vid
        random.shuffle(videos)
        self.play_video(videos[0].video_id)
        # print("play_random_video needs implementation")

    def pause_video(self):
        """Pauses the current video."""

        print("pause_video needs implementation")
    # 1. Check if a video is playing
        if self._video_playing is None:
            print("Cannot pause video: No video is currently playing")
            return
        # 2. Check if the video is already paused
        if self._video_paused:
            print("Video already paused: {0}".format(self._video_playing.title))
            return
        # 3. Pause the video
        print("Pausing video: {0}".format(self._video_playing.title))
        self._video_paused = True
        # print("pause_video needs implementation")

    def continue_video(self):
        """Resumes playing the current video."""

        print("continue_video needs implementation")
        # 1. Check pause-ability
        if not self._video_playing:
            print("Cannot continue video: No video is currently playing")
            return
        if not self._video_paused:
            print("Cannot continue video: Video is not paused")
            return
        # 2. Continue paused video
        print("Continuing video: {0}".format(self._video_playing.title))
        self._video_paused = False
        # print("continue_video needs implementation")

    def show_playing(self):
        """Displays video currently playing."""

        print("show_playing needs implementation")
        # 1. Check any video playing
        if not self._video_playing:
            print("No video is currently playing")
            return
        # 2. Show the video playing
        print("Currently playing: {0}{1}".format(self._video_playing, " - PAUSED" if self._video_paused else ""))
        # print("show_playing needs implementation")

    def create_playlist(self, playlist_name):
        """Creates a playlist with a given name.

        Args:
            playlist_name: The playlist name.
        """
        print("create_playlist needs implementation")
        # 1. find if there is any playlist with same name exists
        exist_playlist = self.is_playlist_exist(playlist_name)
        if exist_playlist:
            print("Cannot create playlist: A playlist with the same name already exists")
            return
        # 2. Create playlist and append to the list of playlists
        new_playlist = Playlist(self, playlist_name)
        self._playlists.append(new_playlist)
        print("Successfully created new playlist: {0}".format(new_playlist.get_name()))
        # print("create_playlist needs implementation")

    def add_to_playlist(self, playlist_name, video_id):
        """Adds a video to a playlist with a given name.

        Args:
            playlist_name: The playlist name.
            video_id: The video_id to be added.
        """
        print("add_to_playlist needs implementation")

        # 1. Check if playlist exists
        exist_playlist = self.is_playlist_exist(playlist_name)
        if not exist_playlist:
            print("Cannot add video to {0}: Playlist does not exist".format(playlist_name))
            return
        # 2. Pass the job to the playlist to add
        exist_playlist.add_video(playlist_name, video_id)
        # print("add_to_playlist needs implementation")

    def show_all_playlists(self):
        """Display all playlists."""
        if len(self._playlists) == 0:
            print("No playlists exist yet")
            return

        print("Showing all playlists:")
        for playlist in sorted(self._playlists, key=lambda pl: pl.get_name()):
            print("\t{0}".format(playlist.get_name()))

    def show_playlist(self, playlist_name):
        """Display all videos in a playlist with a given name.

        Args:
            playlist_name: The playlist name.
        """
        print("show_playlist needs implementation")
        # 1. Check if playlist exists
        exist_playlist = self.is_playlist_exist(playlist_name)
        if not exist_playlist:
            print("Cannot show playlist {0}: Playlist does not exist".format(playlist_name))
            return
        # 2. Show videos
        print("Showing playlist: {0}".format(playlist_name))
        exist_playlist_videos = exist_playlist.get_videos()
        if len(exist_playlist_videos) == 0:
            print("\tNo videos here yet")
            return
        for vid in exist_playlist_videos.values():
            # Part 4 FLAG_VIDEO task: add flag when showing flagged videos
            print("\t{0}{1}".format(vid, " - FLAGGED (reason: {0})".format(vid.flag) if vid.flag else ""))
        # print("show_playlist needs implementation")

    def remove_from_playlist(self, playlist_name, video_id):
        """Removes a video to a playlist with a given name.

        Args:
            playlist_name: The playlist name.
            video_id: The video_id to be removed.
        """
        print("remove_from_playlist needs implementation")
        # 1. Check if playlist exists
        exist_playlist = self.is_playlist_exist(playlist_name)
        if not exist_playlist:
            print("Cannot remove video from {0}: Playlist does not exist".format(playlist_name))
            return
        # 2. Pass the job to the playlist
        exist_playlist.remove_video(playlist_name, video_id)
        # print("remove_from_playlist needs implementation")

    def clear_playlist(self, playlist_name):
        """Removes all videos from a playlist with a given name.

        Args:
            playlist_name: The playlist name.
        """
        print("clears_playlist needs implementation")
        # 1. Check if playlist exists
        exist_playlist = self.is_playlist_exist(playlist_name)
        if not exist_playlist:
            print("Cannot clear playlist {0}: Playlist does not exist".format(playlist_name))
            return
        # 2. Pass the job to the playlist
        exist_playlist.clear(playlist_name)
        # print("clears_playlist needs implementation")

    def delete_playlist(self, playlist_name):
        """Deletes a playlist with a given name.

        Args:
            playlist_name: The playlist name.
        """
        print("deletes_playlist needs implementation")
        # 1. Check if playlist exists
        exist_playlist = self.is_playlist_exist(playlist_name)
        if not exist_playlist:
            print("Cannot delete playlist {0}: Playlist does not exist".format(playlist_name))
            return
        # 2. Delete playlist
        self._playlists = [i for i in self._playlists if i.get_name() != playlist_name]
        print("Deleted playlist: {0}".format(playlist_name))
        # print("deletes_playlist needs implementation")

    def search_videos(self, search_term):
        """Display all the videos whose titles contain the search_term.

        Args:
            search_term: The query to be used in search.
        """
        print("search_videos needs implementation")
        # Pass to Helper Function
        self.search_videos_general(search_term, lambda vid: search_term.lower() in vid.title.lower())
        # print("search_videos needs implementation")

    def search_videos_tag(self, video_tag):
        """Display all videos whose tags contains the provided tag.

        Args:
            video_tag: The video tag to be used in search.
        """
        print("search_videos_tag needs implementation")

        print("search_videos_tag needs implementation")
        # Pass to Helper Function
        self.search_videos_general(video_tag, lambda vid: video_tag.lower() in ";".join(vid.tags).lower().split(";"))
        # print("search_videos_tag needs implementation")

    def flag_video(self, video_id, flag_reason=""):
        """Mark a video as flagged.

        Args:
            video_id: The video_id to be flagged.
            flag_reason: Reason for flagging the video.
        """
        print("flag_video needs implementation")
        # 1. Search video by id
        video_result = self._video_library.get_video(video_id)
        if video_result is None:
            print("Cannot flag video: Video does not exist")
            return
        # 2. Check if the video is flagged
        if video_result.flag:
            print("Cannot flag video: Video is already flagged")
            return
        # 3. Stop playing-video and Flag the video
        # 3.1. check if the playing vid is the one to flag
        if self._video_playing and self._video_playing.video_id == video_id:
            self.stop_video()
        if flag_reason == "":
            flag_reason = "Not supplied"
        video_result.action_flag(flag_reason)
        print("Successfully flagged video: {0} (reason: {1})".format(video_result.title, video_result.flag))
        # print("flag_video needs implementation")

    def allow_video(self, video_id):
        """Removes a flag from a video.

        Args:
            video_id: The video_id to be allowed again.
        """
        print("allow_video needs implementation")
        # 1. Search video by id
        video_result = self._video_library.get_video(video_id)
        if video_result is None:
            print("Cannot remove flag from video: Video does not exist")
            return
        # 2. Check if the video is not flagged
        if not video_result.flag:
            print("Cannot remove flag from video: Video is not flagged")
            return
        # 3. Remove the flag
        video_result.remove_flag()
        print("Successfully removed flag from video: {0}".format(video_result.title))
        # print("allow_video needs implementation")

    # ===========HELPER FUNCTIONS=======================================================================================
    # Custom Helper Function for Part 2
    def is_playlist_exist(self, playlist_name):
        """
        Return if requested playlist exists
        :param playlist_name:
        :return:
        """
        return next((pl for pl in self._playlists if pl.get_name().lower() == playlist_name.lower()), None);

    # Custom Helper Function for Part 3
    def search_videos_general(self, search_keyword, search_filter):
        """
        General Helper Function for search videos
        :param search_keyword:
        :param search_filter:
        :return:
        """
        # 1. Search matching results
        search_results = sorted(
            list(filter(search_filter, self._video_library.get_all_videos())),
            key=lambda vid: vid.title)
        # 2. Part 4 FLAG_VIDEO task: Filter out flagged video
        search_results = list(filter(lambda vid: not vid.flag, search_results))
        # 2. Return if no search results
        if len(search_results) == 0:
            print("No search results for {0}".format(search_keyword))
            return
        # 3. Print results
        print("Here are the results for {0}:".format(search_keyword))
        for i, vid in enumerate(search_results, start=1):
            print("\t{0}) {1}".format(i, vid))
        # 4. Ask user to play or not
        print("Would you like to play any of the above? If yes, specify the number of the video.")
        print("If your answer is not a valid number, we will assume it's a no.")
        # 5. Check and Use regex to get valid number
        is_numeric = re.search(r'^\d+$', input())
        if not is_numeric:
            return
        user_input = int(is_numeric.group())
        if not (1 <= user_input <= len(search_results)):
            return
        # 6. Play the selected video
        self.play_video(search_results[user_input - 1].video_id)


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

def load_json():
	print("Started Reading JSON file")
	with open("color_counts.json", "r") as read_file:
		print("Converting JSON encoded data into Python dictionary")
		counts = json.load(read_file)
	return counts
	#	print("Decoded JSON Data From File")
		#for key, value in developer.items():
		#	print(key, ":", value)
	#	print("Done reading json file")

def prep_data():
	counts = load_json()

	colors = list(counts["prius"].keys())

	# Create Labels
	for key in counts["vehicle"].keys():
		if key not in colors:
			colors.append(key)

	# Create Prius Values
	prius_values = []
	vehicle_values = []
	for color in colors:
		if color in counts["prius"].keys():
			prius_values.append(counts["prius"][color])
		else:
			prius_values.append(0)

		if color in counts["vehicle"].keys():
			vehicle_values.append(counts["vehicle"][color])
		else:
			vehicle_values.append(0)

	return colors, prius_values, vehicle_values

def grouped_bar_chart():
	labels, prius_values, vehicle_values = prep_data()

	x = np.arange(len(labels))  # the label locations
	width = 0.35  # the width of the bars

	fig, ax = plt.subplots()
	rects1 = ax.bar(x - width / 2, prius_values, width, label='Prius')
	rects2 = ax.bar(x + width / 2, vehicle_values, width, label='Vehicle')

	# Add some text for labels, title and custom x-axis tick labels, etc.
	ax.set_ylabel('Color Counts')
	ax.set_title('Vehicles by Color')
	ax.set_xticks(x)
	ax.set_xticklabels(labels)
	ax.legend()

	def autolabel(rects):
		"""Attach a text label above each bar in *rects*, displaying its height."""
		for rect in rects:
			height = rect.get_height()
			ax.annotate('{}'.format(height),
			            xy=(rect.get_x() + rect.get_width() / 2, height),
			            xytext=(0, 3),  # 3 points vertical offset
			            textcoords="offset points",
			            ha='center', va='bottom')
	plt.xticks(rotation=50)

	autolabel(rects1)
	autolabel(rects2)

	fig.tight_layout()

	plt.show()

grouped_bar_chart()


def lineUp(commands):
    position = ['face_front', 'face_left', 'face_back', 'face_right']
    studentA, studentB = 0, 0
    counter = 0
    for i in list(commands):
        if i == 'L':
            studentA += 1
            studentB -= 1
        elif i == 'R':
            studentA -= 1
            studentB += 1
        elif i == 'A':
            studentA += 2
            studentB += 2
        if studentA >= 4:
            studentA -= 4
        if studentA <= -5:
            studentA += 4
        if studentB >= 4:
            studentB -= 4
        if studentB <= -5:
            studentB += 4
        if position[studentA] == position[studentB]:
            counter += 1
    return counter

def lineUp(commands):
    # copy from others
    weird = False
    total = 0
    for command in commands:
        if command == 'L' or command == 'R':
            weird = not weird
        if not weird:
            total += 1
    return total


'''Интерфейс'''

from tkinter import *
from tkinter import filedialog
from Image_processing import *

'''Сохраняем путь к файлу'''
def mfileopen():
    file1 = filedialog.askopenfile()
    file = file1.name
    print(file)
    Deystvie(file)

'''Выбор действия'''
def Deystvie(file):
    dey = Tk()
    dey.title('Фильтры')
    Label(dey, text='Выбирете действие которое необходимо \n'
                    ' сделать с изображением').pack(side=TOP)
    Label(dey, text=file).pack(side=TOP)
    Button(dey, text='Оттенки серого', command=lambda: (IMG_shade_of_gray(file), dey.quit())).pack(side=TOP)
    Button(dey, text='Негатив', command=lambda: (IMG_Negativity(file), dey.quit())).pack(side=TOP)
    Button(dey, text='Сепия', command=lambda: (interf_sepia(file), dey.quit())).pack(side=TOP)
    Button(dey, text='Добавление шумов', command=lambda: (adding_noise(file), dey.quit())).pack(side=TOP)
    Button(dey, text='Яркость', command=lambda: (brightness(file), dey.quit())).pack(side=TOP)
    Button(dey, text='Чернно-белое', command=lambda: (black_white(file), dey.quit())).pack(side=TOP)

def black_white(file):
    sep = Tk()
    sep.title('Чернно-белое')
    Label(sep, text='Введите значение черного, чем болье значение, \n'
                    'тем больше черного, отричательные значения учитываются').pack(side=TOP)
    shade = Entry(sep)
    shade.pack(side=TOP)
    Button(sep, text='Принять', command=lambda: (IMG_Black_White(file, shade), sep.quit())).pack(side=TOP)
    sep.mainloop()

def brightness(file):
    sep = Tk()
    sep.title('Яркость')
    Label(sep, text='Введите значение яркости, чем \n'
                    ' больше значение тем ярче картинка, \n '
                    'отрицательные значения затемняют изображение').pack(side=TOP)
    brig = Entry(sep)
    brig.pack(side=TOP)
    Button(sep, text='Принять', command=lambda: (IMG_Brightness(file, brig), sep.quit())).pack(side=TOP)
    sep.mainloop()

def adding_noise(file):
    sep = Tk()
    sep.title('кол-во шумов')
    Label(sep, text='Введите кол-во шумов, чем больше значение \n'
                    ' тем более шумное изображение получите').pack(side=TOP)
    kol_vo = Entry(sep)
    kol_vo.pack(side=TOP)
    Button(sep, text='Принять', command=lambda: (IMG_Adding_Noise(file, kol_vo), sep.quit())).pack(side=TOP)
    sep.mainloop()

def interf_sepia(file):
    sep = Tk()
    sep.title('Глубина')
    Label(sep, text='Введите глубину, чем больше значение \n'
                    ' тем более сильнее виден коричкевый оттенок, \n'
                    ' чем меньше, тем более видет серый').pack(side=TOP)
    glubina = Entry(sep)
    glubina.pack(side=TOP)
    Button(sep, text='Принять', command=lambda :(IMG_Sepia(file, glubina), sep.quit())).pack(side=TOP)
    sep.mainloop()

top = Tk()
top.title('Фото')
Label(top, text='Выберите фотографию которую \n'
                ' необходимо преобразовать').pack(side=TOP)

Button(top, text='open file', command=mfileopen).pack(side=TOP) #отрываем файл

top.mainloop()


# -*- coding: utf-8 -*-
# from modeledcommandparameter import *
from modeledcommandparameter import ModeledCommandParameter

class Material(ModeledCommandParameter):

    """
    A Material is a:
    (1) MTAG (A) material composition tag
    (2) MGEOM (A) material geometry tag
    (3-12) GPARM (R) 10 parameters that describe the geometry of the material

    Enter MTAG in upper case.
    Valid MTAG'S are:

    VAC vacuum (i.e., no material)
    GH gaseous hydrogen
    GHE gaseous helium
    LH liquid hydrogen
    LHE liquid helium
    LI BE B C AL TI FE CU W HG PB (elements)
    LIH lithium hydride
    CH2 polyethylene
    SS stainless steel (alloy 304)

    Valid MGEOM's are:

    NONE use for vacuum
    10*0.

    CBLOCK cylindrical block
    10*0.
    ...

    """
    begtag = ''
    endtag = ''

    materials = {
        'VAC': {'desc': 'Vacuum (no material)', 'icool_material_name': ''},
        'GH': {'desc': 'Gaseous hydrogen'},
        'GHE': {'desc': 'Gaseous helium'},
        'LH': {'desc': 'Liquid hydrogen'},
        'LHE': {'desc': 'Liquid helium'},
        'LI': {'desc': 'Lithium'},
        'BE': {'desc': 'Berylliyum'},
        'B': {'desc': 'Boron'},
        'C': {'desc': 'Carbon'},
        'AL': {'desc': 'Aluminum'},
        'TI': {'desc': 'Titanium'},
        'FE': {'desc': 'Iron'},
        'CU': {'desc': 'Copper'},
        'W': {'desc': 'Tungsten'},
        'HG': {'desc:': 'Mercury'},
        'PB': {'desc:': 'Lead'}
    }

    models = {
        'model_descriptor': {
            'desc': 'Geometry',
            'name': 'geom',
            'num_parms': 12,
            'for001_format': {
                'line_splits': [1, 1, 10]}},
        'VAC': {
            'desc': 'Vacuum',
            'doc': 'Vacuum region.  Specify vacuum for mtag.  Geom will be set to NONE.',
            'parms': {
                'mtag': {
                           'pos': 1, 'type': 'String', 'doc': ''}}},
        'CBLOCK': {
            'desc': 'Cylindrical block',
            'doc': 'Cylindrical block',
            'parms': {
                'mtag': {
                    'pos': 1, 'type': 'String', 'doc': ''},
                'geom': {
                    'pos': 2, 'type': 'String', 'doc': ''}}},
        'ASPW': {
            'desc': 'Azimuthally Symmetric Polynomial Wedge absorber region', 'doc': 'Edge shape given by '
                    'r(dz) = a0 + a1*dz + a2*dz^2 + a3*dz^3 in the 1st quadrant and '
                    'where dz is measured from the wedge center. '
                    '1 z position of wedge center in region [m] '
                    '2 z offset from wedge center to edge of absorber [m] '
                    '3 a0 [m] '
                    '4 a1 '
                    '5 a2 [m^(-1)] '
                    '6 a3 [m^(-2)]',
            'parms': {
                'mtag': {
                    'pos': 1, 'type': 'String', 'doc': ''},
                'geom': {
                    'pos': 2, 'type': 'String', 'doc': ''},
                'zpos': {
                    'pos': 3, 'type': 'Real', 'doc': ''},
                'zoff': {
                    'pos': 4, 'type': 'Real', 'doc': ''},
                'a0': {
                    'pos': 5, 'type': 'Real', 'doc': ''},
                'a1': {
                    'pos': 6, 'type': 'Real', 'doc': ''},
                'a2': {
                    'pos': 7, 'type': 'Real', 'doc': ''},
                'a3': {
                    'pos': 8, 'type': 'Real', 'doc': ''}}},
        'ASRW': {
            'desc': 'Azimuthally Symmetric Polynomial Wedge absorber region',
            'doc':  'Edge shape given by '
                    'r(dz) = a0 + a1*dz + a2*dz^2 + a3*dz^3 in the 1st quadrant and '
                    'where dz is measured from the wedge center. '
                    '1 z position of wedge center in region [m] '
                    '2 z offset from wedge center to edge of absorber [m] '
                    '3 a0 [m] '
                    '4 a1 '
                    '5 a2 [m^(-1)] '
                    '6 a3 [m^(-2)]',
            'parms': {
                'mtag': {
                    'pos': 1, 'type': 'String', 'doc': ''},
                'geom': {
                    'pos': 2, 'type': 'String', 'doc': ''},
                'zpos': {
                    'pos': 3, 'type': 'Real', 'doc': ''},
                'zoff': {
                    'pos': 4, 'type': 'Real', 'doc': ''},
                'a0': {
                    'pos': 5, 'type': 'Real', 'doc': ''},
                'a1': {
                    'pos': 6, 'type': 'Real', 'doc': ''},
                'a2': {
                    'pos': 7, 'type': 'Real', 'doc': ''},
                'a3': {
                    'pos': 8, 'type': 'Real', 'doc': ''}}},
        'HWIN': {
            'desc': 'Hemispherical absorber end region',
            'doc': '1 end flag {-1: entrance, +1: exit} '
                   '2 inner radius of window[m] '
                   '3 window thickness [m] '
                   '4 axial offset of center of spherical window from start of end region [m]',
            'parms': {
                'mtag': {
                    'pos': 1, 'type': 'String', 'doc': ''},
                'geom': {
                    'pos': 2, 'type': 'String', 'doc': ''},
                'end_flag': {
                    'pos': 3, 'type': 'Real', 'doc': '1 end flag {-1: entrance, +1: exit} '},
                'in_rad': {
                    'pos': 4, 'type': 'Real', 'doc': 'Inner radius of window'},
                'thick': {
                    'pos': 5, 'type': 'Real', 'doc': 'Thickness of window'},
                'offset': {
                    'pos': 6, 'type': 'Real', 'doc': 'Axial offset of center of spherical '
                                                     'window from start of end region [m]'}}},
        'NIA': {
            'desc': 'Non-isosceles absorber',
            'doc': '1 zV distance of wedge “center” from start of region [m] '
                   '2 z0 distance from center to left edge [m] '
                   '3 z1 distance from center to right edge [m] '
                   '4 θ0 polar angle from vertex of left edge [deg] '
                   '5 φ0 azimuthal angle of left face [deg] '
                   '6 θ1 polar angle from vertex of right edge [deg] '
                   '7 φ1 azimuthal angle of right face [deg]',
            'parms': {
                'mtag': {
                    'pos': 1, 'type': 'String', 'doc': ''},
                'geom': {
                    'pos': 2, 'type': 'String', 'doc': ''},
                'zv': {
                    'pos': 3, 'type': 'Real', 'doc': 'Distance of wedge “center” from start of region [m]'},
                'z0': {
                    'pos': 4, 'type': 'Real', 'doc': 'Distance from center to left edge [m] '},
                'z1': {
                    'pos': 5, 'type': 'Real', 'doc': 'Distance from center to right edge [m]}'},
                'θ0': {
                    'pos': 6, 'type': 'Real', 'doc': 'Polar angle from vertex of left edge [deg]'},
                'φ0': {
                    'pos': 7, 'type': 'Real', 'doc': 'Azimuthal angle of left face [deg]'},
                'θ1': {
                    'pos': 8, 'type': 'Real', 'doc': 'Polar angle from vertex of right edge [deg] '},
                'φ1': {
                    'pos': 9, 'type': 'Real', 'doc': 'Azimuthal angle of right face [deg]'}}},
        'PWEDGE': {
            'desc': 'Asymmetric polynomial wedge absorber region',
            'doc': 'Imagine the wedge lying with its narrow end along the x axis. The wedge is symmetric about the '
                   'x-y plane. The edge shape is given by dz(x) = a0 + a1*x + a2*x^2 + a3*x^3 '
                   'where dz is measured from the x axis.',
            'parms': {
                'mtag': {
                    'pos': 1, 'type': 'String', 'doc': ''},
                'geom': {
                    'pos': 2, 'type': 'String', 'doc': ''},
                'init_vertex': {
                    'pos': 3, 'type': 'Real', 'doc': 'Initial position of the vertex along the x axis [m]'},
                'z_wedge_vertex': {
                    'pos': 4, 'type': 'Real', 'doc': 'z position of wedge vertex [m] '},
                'az': {
                    'pos': 5, 'type': 'Real', 'doc': 'Azimuthal angle of vector pointing to vertex in plane of wedge w.r.t. +ve x-axis [deg]'},
                'width': {
                    'pos': 6, 'type': 'Real', 'doc': 'Total width of wedge in dispersion direction [m]'},
                'height': {
                    'pos': 7, 'type': 'Real', 'doc': 'Total height of wedge in non-dispersion direction [m]'},
                'a0': {
                    'pos': 8, 'type': 'Real', 'doc': 'Polar angle from vertex of right edge [deg] '},
                'a1': {
                    'pos': 9, 'type': 'Real', 'doc': 'Azimuthal angle of right face [deg]'},
                'a2': {
                    'pos': 10, 'type': 'Real', 'doc': 'Polar angle from vertex of right edge [deg] '},
                'a3': {
                    'pos': 11, 'type': 'Real', 'doc': 'Azimuthal angle of right face [deg]'}}},
        'RING': {
            'desc': 'Annular ring of material',
            'doc': 'This is functionally equivalent to defining a region with two radial subregions, the first of '
                   'which has vacuum as the material type. However, the boundary crossing algorithm used for RING is '
                   'more sophisticated and should give more accurate simulations.',
            'parms': {
                'mtag': {
                    'pos': 1, 'type': 'String', 'doc': ''},
                'geom': {
                    'pos': 2, 'type': 'String', 'doc': ''},
                'inner': {
                    'pos': 3, 'type': 'Real', 'doc': 'Inner radius (R) [m]'},
                'outer': {
                    'pos': 4, 'type': 'Real', 'doc': 'Outer radius (R) [m]'}}},
        'WEDGE': {
            'desc': 'Asymmetric wedge absorber region',
            'doc': 'We begin with an isosceles triangle, sitting on its base, vertex at the top. '
                   'The base-to-vertex distance is W. The full opening angle at the vertex is A. Using '
                   'two of these triangles as sides, we construct a prism-shaped wedge. The distance from '
                   'one triangular side to the other is H. The shape and size of the wedge are now established. '
                   'We define the vertex line of the wedge to be the line connecting the vertices of its two '
                   'triangular sides.  Next, we place the wedge in the right-handed ICOOL coordinate system. '
                   'The beam travels in the +Z direction. Looking downstream along the beamline (+Z into the page), '
                   '+X is horizontal and to the left, and +Y is up.  Assume the initial position of the wedge is as '
                   'follows: The vertex line of the wedge is vertical and lies along the Y axis, extending from Y = -H/2 '
                   'to Y = +H/2. The wedge extends to the right in the direction of -X, such that it is symmetric about '
                   "the XY plane. (Note that it is also symmetric about the XZ plane.) From the beam's point of view, "
                   'particles passing on the +X side of the Y axis will not encounter the wedge, while particles passing '
                   'on the -X side of the Y axis see a rectangle of height H and width W, centered in the Y direction, with '
                   'Z thickness proportional to -X.  '
                   'By setting parameter U to a non-zero value, the user may specify that the wedge is to be '
                   'translated in the X direction. If U>0, the wedge is moved (without rotation) in the +X direction. '
                   'For example, if U = W/2, then the wedge is centered in the X direction; its vertex is at X = W/2 '
                   'and its base is at X = -W/2. Note that the wedge is still symmetric about both the XY plane and '
                   'the XZ plane. '
                   'Next, the wedge may be rotated about the Z axis by angle PHI. Looking downstream in the beam '
                   'direction, positive rotations are clockwise and negative rotations are counter-clockwise. For '
                   'example, setting PHI to 90 degrees rotates the wedge about the Z axis so that its vertex line is '
                   'parallel to the X axis and on top, while its base is parallel to the XZ plane and at the bottom. In '
                   'general this rotation breaks the symmetry about the XZ plane, but the symmetry about the XY '
                   'plane is maintained. '
                   'Finally, the wedge is translated in the Z direction by a distance Zv, so that its XY symmetry plane '
                   'lies a distance Zv downstream of the start of the region. Usually Zv should be at least large '
                   'enough so that the entire volume of the wedge lies within its region, i.e. Zv .ge. W tan (A/2), the '
                   'maximum Z half-thickness of the wedge. As well, the region usually should be long enough to '
                   'contain the entire volume of the wedge, i.e. RegionLength .ge. Zv + W tan (A/2). Wedges that do '
                   'lie completely within their region retain their symmetry about the XY plane Z=Zv.  '
                   'If portions of a wedge lie outside their region in Z, then the volume of the wedge lying outside '
                   'the region is ignored when propagating particles through the wedge. Such a wedge will grow in '
                   'thickness until it reaches the region boundary, but will not extend beyond it. In such cases, '
                   'wedges may lose their symmetry about the XY plane Z=Zv.'
                   'Wedges may be defined such that they extend outside the radial boundaries of the radial '
                   'subregion within which they are defined. However, any portion of the wedge volume lying inside the inner '
                   'radial boundary or outside the outer radial boundary is ignored when propagating particles through '
                   'the wedge. For example, if the user intends that an entire radial subregion of circular cross-section be '
                   'filled with a wedge, then it is clear that the corners of the wedge must extend outside the radial region, '
                   "but particles passing outside the wedge's radial subregion will not see the wedge at all.  "
                   'In short, we may say that although it is permitted (and sometimes essential) to define a wedge to '
                   'be larger than its subregion, for the purposes of particle propagation the wedge is always trimmed at the '
                   "region's Z boundaries and the subregion's radial boundaries. Any volume within the region and subregion "
                   'that is not occupied by the material specified for the wedge is assumed to be vacuum.'
                   '------------------------------------------------------------------------------------------------------------'
                   'Example 1: Within a region 0.4 meters long in Z, within a radial subregion extending from the Z axis out '
                   'to a radius of 0.3 meters, a wedge is to fill the X<0 (right) half of the 0.3 meter aperture of the '
                   'subregion, and increase in Z thickness proportional to -X, such that it is 0.2 meters thick at the '
                   'rightmost point in the subregion (X=-0.3, Y=0).  The wedge is to be 0.2 meters thick at a point 0.3 '
                   'meters from its vertex. The half-thickness is 0.1 meters, the half-opening angle is '
                   'atan (0.1/0.3) = 18.4 degrees, so the full opening angle of the wedge A is 36.8 degrees. The width '
                   '(X extent) of the wedge must be 0.3 meters, and the height (Y extent) of the wedge must be 0.6 meters. '
                   'Two corners of the wedge extend well beyond the subregion, but they will be ignored during particle '
                   'propagation. The wedge does not need to be translated in X (U = 0) nor does it need to be rotated '
                   'about the Z axis (PHI = 0). For convenience we center the wedge (in Z) within its region, '
                   'so Zv = 0.2 meters. Since the maximum half-thickness of the wedge is only 0.1 meters, the wedge '
                   'does not extend beyond (or even up to) the Z boundaries of the region. The volume within the region '
                   'and subregion but outside the wedge is assumed to be vacuum.'
                   '------------------------------------------------------------------------------------------------------------'
                   'Example 2: In the same region and subregion, we need a wedge with the same opening angle, '
                   'but filling the entire aperture of the subregion, thickness gradient in the +Y direction, thickness = '
                   '0 at the lowest point in the subregion (X=0, Y=-0.3).'
                   'The wedge must now have H = W = 0.6 meters so it can fill the entire aperture of the subregion.'
                   'From its initial position, it must first be translated 0.3 meters in the +X direction (U = 0.3) to '
                   "center it in the subregion's aperture, and then (from the perspective of someone looking "
                   'downstream along the beam) rotated counterclockwise 90 degrees (PHI = -90.) so that the Z '
                   'thickness increases proportionally to +Y. Since the wedge has the same opening angle as before '
                   'but has twice the width, its maximum Z thickness is now 0.4 meters, just barely fitting between '
                   'the Z boundaries of the region if Zv = 0.2 meters. All four corners of the wedge now extend '
                   "outside the radial subregion's outer boundary, but they will be ignored during particle "
                   'propagation.” {S.B.}'
                   'The wedge geometry can accept a second MTAG parameter in the SREGION construct. The first material '
                   'refers to the interior of the wedge. The second material, if present, refers to the exterior of the wedge. '
                   'If a second MTAG parameter is not present, vacuum is assumed.',
            'parms': {
                'mtag': {
                    'pos': 1, 'type': 'String', 'doc': ''},
                'geom': {
                    'pos': 2, 'type': 'String', 'doc': ''},
                'vert_ang': {
                    'pos': 3, 'type': 'Real', 'doc': 'Full angle at vertex, α (or A) [degrees]the x axis [m]'},
                'vert_init': {
                    'pos': 4, 'type': 'Real', 'doc': 'Initial position of the vertex along the x axis, U [m]'},
                'vert_z': {
                    'pos': 5, 'type': 'Real', 'doc': 'Z position of wedge vertex, Zv [m]'},
                'vert_az': {
                    'pos': 6, 'type': 'Real', 'doc': 'azimuthal angle φ of vector pointing to vertex in plane of wedge w.r.t. +ve x-axis [deg]'},
                'width': {
                    'pos': 7, 'type': 'Real', 'doc': 'Total width of wedge in dispersion direction, w [m]'},
                'height': {
                    'pos': 8, 'type': 'Real', 'doc': 'Total height of wedge in non-dispersion direction, h [m]'}}}}

    def __init__(self, **kwargs):
        if ModeledCommandParameter.check_command_params_init(self, Material.models, **kwargs) is False:
            sys.exit(0)

    def __setattr__(self, name, value):
        self.__modeled_command_parameter_setattr__(name, value, Material.models)

    def __str__(self):
        return 'Material:' + ModeledCommandParameter.__str__(self)

    """def gen_mparm(self):
        self.mparm = [0] * 12
        cur_model = self.get_model_dict(self.geom)
        for key in cur_model:
            pos = int(cur_model[key]['pos']) - 1
            val = getattr(self, key)
            self.mparm[pos] = val
        print self.mparm

    def gen(self, file):
        file.write('\n')
        file.write(self.mtag)
        file.write('\n')
        file.write(self.mgeom)
        file.write('\n')
        for s in mparm:
            file.write(s)
            file.write(" ")"""


from torchtext import data
from torchtext import datasets
import spacy
import argparse
import torch
import numpy as np
import torch.nn as nn
import torch.distributions #this package provides a lot of nice abstractions for policy gradients
from torch.autograd import Variable
import torch.nn.functional as F
import torch.optim as optim
from tqdm import tqdm
import pickle
import math
from numpy import inf
import sandbox_nmt

def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("--devid", type=int, default=-1)

    parser.add_argument("--model", choices=["Soft"], default="Soft")
    parser.add_argument("--preprocess", choices=["On", "Off"], default="Off")

    parser.add_argument("--minfreq", type=int, default=5)
    parser.add_argument("--sentlen", type=int, default=20)

    parser.add_argument("--bidirectional_encoder", choices=["On", "Off"], default="On")
    parser.add_argument("--nhid", type=int, default=200)
    parser.add_argument("--adddim", type=int, default=512)
    parser.add_argument("--embdim", type=int, default=200)
    parser.add_argument("--nlayers_enc", type=int, default=1)
    parser.add_argument("--nlayers_dec", type=int, default=1)
    parser.add_argument("--maxout", type=int, default=1000)

    parser.add_argument("--maxnorm", type=float, default=None)
    parser.add_argument("--dropout", type=float, default=0.3)

    parser.add_argument("--epochs", type=int, default=13)

    parser.add_argument("--optim", choices=["Adadelta", "Adam", "SGD"], default="SGD")

    parser.add_argument("--lr", type=float, default=0.0001)
    parser.add_argument("--rho", type=float, default=0.95)
    parser.add_argument("--lrd", type=float, default=0.5)
    parser.add_argument("--wd", type=float, default=1e-4)

    parser.add_argument("--bsize", type=int, default=64)
    parser.add_argument("--clip", type=float, default=1)

    # Adam parameters
    parser.add_argument("--b1", type=float, default=0.9)
    parser.add_argument("--b2", type=float, default=0.999)
    parser.add_argument("--eps", type=float, default=1e-8)

    return parser.parse_args()

args = parse_args()

#Turn off CuDNN
torch.manual_seed(1111)
if args.devid >= 0:
    torch.cuda.manual_seed_all(1111)
    torch.backends.cudnn.enabled = False
    print("Cudnn is enabled: {}".format(torch.backends.cudnn.enabled))

padidx_en = -1

def preprocess():

    print("Preprocessing Data")

    #Setup Dataset
    spacy_de = spacy.load('de')
    spacy_en = spacy.load('en')

    def tokenize_de(text):
        return [tok.text for tok in spacy_de.tokenizer(text)]

    def tokenize_en(text):
        return [tok.text for tok in spacy_en.tokenizer(text)]

    #Add beginning and end tokens to target sentences
    BOS_WORD = '<s>'
    EOS_WORD = '</s>'
    DE = data.Field(tokenize=tokenize_de)
    EN = data.Field(tokenize=tokenize_en, init_token = BOS_WORD, eos_token = EOS_WORD) # only target needs BOS/EOS

    train, val, test = datasets.IWSLT.splits(exts=('.de', '.en'), fields=(DE, EN),
                                             filter_pred=lambda x: len(vars(x)['src']) <= args.sentlen and
                                             len(vars(x)['trg']) <= args.sentlen)

    #Replace tokens that appear less than minfreq times as <unk>
    DE.build_vocab(train.src, min_freq=args.minfreq)
    EN.build_vocab(train.trg, min_freq=args.minfreq)

    vocab = [DE.vocab, EN.vocab]

    train_iter, val_iter = data.BucketIterator.splits((train, val), batch_size=args.bsize, device=args.devid,
                                                      repeat=False, sort_key=lambda x: len(x.src))

    #process source_test data
    test_x = []
    with open('source_test.txt') as fp:
        for line in fp:
            line_vec = DE.process(line, device=args.devid, train=False)
            print(line_vec)
            test_x.append(line_vec)

#    for line in open('source_test.txt'):
#        #line.rstrip('\n')
#        line_vec = DE.process([line], device=args.devid, train=False)
#        print(line_vec)
#        #print(line_vec.src)
#        test_x.append(line_vec)

    train_x = []
    train_y = []
    for batch in tqdm(train_iter):
        train_x.append(batch.src)
        train_y.append(batch.trg)

    val_x = []
    val_y = []
    for batch in tqdm(val_iter):
        val_x.append(batch.src)
        val_y.append(batch.trg)

    with open('train_x.pkl', 'wb') as output:  # Overwrites any existing file.
        pickle.dump(train_x, output, pickle.HIGHEST_PROTOCOL)

    with open('train_y.pkl', 'wb') as output:  # Overwrites any existing file.
        pickle.dump(train_y, output, pickle.HIGHEST_PROTOCOL)

    with open('val_x.pkl', 'wb') as output:  # Overwrites any existing file.
        pickle.dump(val_x, output, pickle.HIGHEST_PROTOCOL)

    with open('val_y.pkl', 'wb') as output:  # Overwrites any existing file.
        pickle.dump(val_y, output, pickle.HIGHEST_PROTOCOL)

    with open('vocab.pkl', 'wb') as output:  # Overwrites any existing file.
        pickle.dump(vocab, output, pickle.HIGHEST_PROTOCOL)

    with open('test_x.pkl', 'wb') as output:  # Overwrites any existing file.
        pickle.dump(test_x, output, pickle.HIGHEST_PROTOCOL)

    print("Data Loaded")

def load_data():
    pkl_train_x = open('train_x.pkl', 'rb')
    pkl_train_y = open('train_y.pkl', 'rb')
    pkl_val_x = open('val_x.pkl', 'rb')
    pkl_val_y = open('val_y.pkl', 'rb')
    pkl_vocab = open('vocab.pkl', 'rb')

    train_x = pickle.load(pkl_train_x)
    train_y = pickle.load(pkl_train_y)
    val_x = pickle.load(pkl_val_x)
    val_y = pickle.load(pkl_val_y)
    de_vocab, en_vocab = pickle.load(pkl_vocab)

    pkl_train_x.close()
    pkl_train_y.close()
    pkl_val_x.close()
    pkl_val_y.close()
    pkl_vocab.close()

    return train_x, train_y, val_x, val_y, de_vocab, en_vocab

class AttnNetwork(nn.Module):
    def __init__(self, vocab_size_de, vocab_size_en, dropout=0, word_dim=args.embdim, hidden_dim=args.nhid, n_layers_enc=args.nlayers_enc, n_layers_dec=args.nlayers_dec,
                 maxout=args.maxout, batch_size=args.bsize, add_dim=args.adddim, bidirect=args.bidirectional_encoder):
        super(AttnNetwork, self).__init__()
        self.attn = []
        self.bidirect = 1
        self.bidirect_toggle = False
        self.nlayers_enc = n_layers_enc
        self.nlayers_dec = n_layers_dec
        if bidirect == "On":
            self.bidirect = 2
            self.bidirect_toggle = True
        self.hidden_dim = hidden_dim
        self.add_dim = add_dim

        self.drop =nn.Dropout(dropout)

        self.encoder = nn.LSTM(word_dim, hidden_dim, num_layers = n_layers_enc, batch_first = True, bidirectional = self.bidirect_toggle, dropout = dropout)
        self.decoder = nn.LSTM(word_dim, hidden_dim, num_layers = n_layers_dec, batch_first = True, dropout = dropout)
        self.embedding_de = nn.Embedding(vocab_size_de, word_dim)
        self.embedding_en = nn.Embedding(vocab_size_en, word_dim)

        #Transformations on multi score
        self.linear_E = nn.Linear(hidden_dim * self.bidirect, hidden_dim)
        self.linear_D = nn.Linear(hidden_dim, hidden_dim)

        #Transformations on add score
#        self.linear_Wa = nn.Linear(hidden_dim, add_dim)
#        self.linear_Ua = nn.Linear(hidden_dim * self.bidirect, add_dim)
#        self.linear_Va = nn.Linear(add_dim, 1)

        #Transformation on context vector
        self.linear_A = nn.Linear(3 * hidden_dim, hidden_dim)
        self.linear_C = nn.Linear(hidden_dim, vocab_size_en)

        self.logsoftmax = nn.LogSoftmax(dim=1)

    def forward(self, x, y, criterion, attn_type=args.model, visualize="Off"):

        emb_de = self.embedding_de(x) # Bsize x Sent Len x Emb Size
        emb_en = self.embedding_en(y)

        h0_enc = Variable(torch.zeros(self.nlayers_enc * self.bidirect, x.size(0), self.hidden_dim).type_as(emb_de.data)) #1 x Bsize x Hidden Dim
        c0_enc = Variable(torch.zeros(self.nlayers_enc * self.bidirect, x.size(0), self.hidden_dim).type_as(emb_de.data))

        enc_h, (h0_enc, c0_enc) = self.encoder(emb_de, (h0_enc, c0_enc)) #32x16x1000; bsize x sent len x hidden

        #Need to change the initialized dec hidden state to the backwards layer of bilstm later...
        h0 = h0_enc[1, :, :].unsqueeze(0)
        c0 = c0_enc[1, :, :].unsqueeze(0)
        #h0 = h0_enc
        #c0 = c0_enc

        dec_h, (h_dec, c_dec) = self.decoder(emb_en[:, :-1], (h0, c0)) #32x21x1000; bsize x sent len -1  x hidden
        dec_h = self.drop(dec_h)

        scores = torch.bmm(self.linear_E(enc_h), self.linear_D(dec_h).transpose(1, 2)) #this will be a batch x source_len x target_len (32x16x21)

        loss = 0

        for i in range(dec_h.size(1)):
            attn_dist = F.softmax(scores[:, :, i], dim=1) #get attention score

            if visualize == "On":
                self.attn.append(attn_dist.data)

            context = torch.bmm(attn_dist.unsqueeze(1), enc_h).squeeze(1) #batch x hidden (32x1000)

            label = y[:, i+1] #start with one word forward since first word is start of sent token

            t = F.tanh(self.linear_A(torch.cat((context, dec_h[:, i]), 1)))

            pred = self.linear_C(t)
            reward = criterion(pred, label)

            loss += reward

        if visualize == "On":
            torch.stack(self.attn, 0).transpose(0, 1)

        return loss

    #predict with greedy decoding
    def predict_greedy(self, x, padidx_s):
        self.eval()

        emb_de = self.embedding_de(x)
        h_enc = Variable(torch.zeros(self.nlayers_enc * self.bidirect, x.size(0), self.hidden_dim).type_as(emb_de.data)) #1 x Bsize x Hidden Dim
        c_enc = Variable(torch.zeros(self.nlayers_enc * self.bidirect, x.size(0), self.hidden_dim).type_as(emb_de.data))

        enc_h, (h, c) = self.encoder(emb_de, (h_enc, c_enc))
        y = [Variable(torch.zeros(x.size(0)).add_(padidx_s).type_as(emb_de.data).long())]

#        h = h[1, :, :].unsqueeze(0)
#        c = c[1, :, :].unsqueeze(0)

        for i in range(1, args.sentlen):
            emb_t = self.embedding_en(y[-1])
            dec_h, (h, c) = self.decoder(emb_t.unsqueeze(1), (h, c))

            #Calculate Scores
            scores = torch.bmm(self.linear_E(enc_h), self.linear_D(dec_h).transpose(1, 2)) #this will be a batch x source_len x target_len (32x16x21)

            attn_dist = F.softmax(scores, dim = 1)
            self.attn.append(attn_dist.data)
            context = torch.bmm(attn_dist.unsqueeze(1), enc_h).squeeze(1)

            #Generate Prediction
            t = F.tanh(self.linear_A(torch.cat((context, dec_h[:, i]), 1)))

            #do I need softmax here? probably not
            pred = self.logsoftmax(self.linear_C(t)) #batchxvocab
            _, next_token = pred.max(1)
            y.append(next_token)

        self.attn = torch.stack(self.attn, 0).transpose(0, 1)
        return torch.stack(y, 0).transpose(0, 1).data

        #predict with beam search
    def predict_beam(self, x, padidx_s, eosidx, en_len,  beam_size=5):
        self.eval()

        start_beam = beam_size

        emb_de = self.embedding_de(x).unsqueeze(0)

        h_enc = Variable(torch.zeros(self.nlayers_enc * self.bidirect, 1, self.hidden_dim).type_as(emb_de.data)) #1 x Bsize x Hidden Dim
        c_enc = Variable(torch.zeros(self.nlayers_enc * self.bidirect, 1, self.hidden_dim).type_as(emb_de.data))

        enc_h, (h, c) = self.encoder(emb_de, (h_enc, c_enc))

        #initialize y with start of sentence token; len is + 2 to deal with begin and end sentence tokens
        start_sen_tok = Variable(torch.zeros(beam_size).add_(padidx_s).type_as(emb_de.data).long())

        #Create a 2D tensor that tracks whether a beam is completed or not (has hit <eos>)
        running_eos = torch.zeros(beam_size).type_as(emb_de.data).long()

        #Create 2D tensor that represents beam_size x predicted word indicies, of best current predictions
        running_beam = torch.zeros(beam_size, args.sentlen).type_as(emb_de.data).long()

        running_beam[:, 0]  = start_sen_tok.data

        # Find best beam_size (unique) first words
        emb_t = self.embedding_en(start_sen_tok[0])

        dec_h, (h, c) = self.decoder(emb_t.unsqueeze(1), (h, c))

        scores = torch.bmm(self.linear_E(enc_h), self.linear_D(dec_h).transpose(1, 2)).squeeze(2) #this will be a batch x source_len x target_len (32x16x21)

        attn_dist = F.softmax(scores, dim = 1)
        context = torch.bmm(attn_dist.unsqueeze(1), enc_h).squeeze(1)

        t = F.tanh(self.linear_A(torch.cat((context, dec_h[:, 0]), 1)))

        pred = self.logsoftmax(self.linear_C(t)) #batchxvocab
        _, predk_indices = pred.topk(beam_size, dim=1)

        #predk_probs will keep track of the current best probabilities for each beam
        predk_probs = torch.gather(pred, 1, predk_indices)

        running_beam[:, 1]  = predk_indices.data

        #Create a list that keeps track of the hidden layers for each copy of the decoder
        # Initialize all 5 beams with decoder hidden state of first layer
        running_hidden = []
        for i in range(beam_size):
            running_hidden.append((h, c))

        #Work on all the words after the start of sentence token
        for w in range(2, args.sentlen):

            cat_probs = torch.FloatTensor().type_as(emb_de.data)
            for i in range(beam_size):

                if running_eos[i] == 0:

                    emb_t = self.embedding_en(Variable(torch.LongTensor([running_beam[i, w-1]]).type_as(running_beam)))

                    h_t, c_t = running_hidden[i]
                    dec_h, (h, c) = self.decoder(emb_t.unsqueeze(1), (h_t, c_t))
                    running_hidden[i] = (h, c)

                    scores = torch.bmm(self.linear_E(enc_h), self.linear_D(dec_h).transpose(1, 2)).squeeze(2)

                    attn_dist = F.softmax(scores, dim = 1)
                    context = torch.bmm(attn_dist.unsqueeze(1), enc_h).squeeze(1)

                    t = F.tanh(self.linear_A(torch.cat((context, dec_h[:, 0]), 1)))
                    pred = self.logsoftmax(self.linear_C(t)) + predk_probs.squeeze(0)[i] #batchxvocab

                    cat_probs = torch.cat((cat_probs, pred.data), 1)

            if beam_size > 0:
                _, predk_indices =cat_probs.topk(beam_size, dim=1)

                gathered_probs = Variable(torch.gather(cat_probs, 1, predk_indices))

                while gathered_probs.size(1) < start_beam:
                    gathered_probs = torch.cat((gathered_probs, predk_probs[:, gathered_probs.size(1)].unsqueeze(0).type_as(predk_probs.data)), 1)

                predk_probs = gathered_probs

                current_ind = torch.remainder(predk_indices, en_len)
                while current_ind.size(1) < start_beam:
                    current_ind = torch.cat((current_ind, torch.LongTensor([[0]])), 1)
                prev_ind = torch.div(predk_indices, en_len)
                while prev_ind.size(1) < start_beam:
                    prev_ind = torch.cat((prev_ind, torch.LongTensor([[prev_ind.size(1)]])), 1)

                running_beam = running_beam[prev_ind, :].squeeze(0)

                running_beam[:, w] = current_ind.transpose(0, 1)
                running_eos += (torch.eq(current_ind.transpose(0, 1), eosidx).long() * w).unsqueeze(1)

                #move completed beams to the bottom of the list, and reduce beam size
                beam_reduce = 0
                counter = beam_size
                i = 0
                while counter > 0:
                    if running_eos[i] > 0:
                        running_beam = sandbox_nmt.move_to_bottom(running_beam, i)
                        predk_probs = sandbox_nmt.move_to_bottom(predk_probs.transpose(0, 1), i).transpose(0, 1)
                        running_eos = sandbox_nmt.move_to_bottom(running_eos.unsqueeze(1), i).squeeze(1)
                        running_hidden.append(running_hidden.pop(i))
                        beam_reduce += 1
                    else:
                        i += 1
                    counter = counter - 1
                beam_size -= beam_reduce

        print(running_beam)

        _, max_index = predk_probs.topk(start_beam,1)

        final_pred = running_beam[max_index.data.squeeze(0), :].type_as(x.data)

        print(final_pred)

        return final_pred

    def gen_predictions(DE):
        #self.eval

        pass

def train(train_iter, model, criterion, optimizer, train_len):
    model.train()
    total_loss = 0
    nwords = 0
    for x, y in tqdm(train_iter):
        x = x.transpose(0, 1)
        y = y.transpose(0, 1)
        optimizer.zero_grad()
        bloss = model.forward(x, y, criterion)
        total_loss += bloss.data[0]
        nwords += y.ne(padidx_en).int().sum()
        bloss.backward()
        torch.nn.utils.clip_grad_norm(model.parameters(), args.clip)
        optimizer.step()

        #total_loss += bloss.data[0] * (x.size(0) / train_len)

    word_loss = total_loss/nwords.data[0]

    return word_loss

def validate(val_iter, model, criterion, val_len, startosidx, eosidx, en_vocab):
    model.eval()
    total_loss = 0
    total_bleu = 0
    nwords = 0
    for x, y in tqdm(val_iter):
        x = x.transpose(0, 1)
        y = y.transpose(0, 1)

        nwords += y.ne(padidx_en).int().sum()
        bloss = model.forward(x, y, criterion)
        total_loss += bloss.data[0]

    word_loss = total_loss/nwords.data[0]

    return word_loss, total_bleu

def escape(l):
    return l.replace("\"", "<quote>").replace(",", "<comma>")

if __name__ == "__main__":
    if args.preprocess == "On":
        preprocess()

    train_x, train_y, val_x, val_y, de_vocab, en_vocab = load_data()
    startosidx = en_vocab.stoi["<s>"]
    eosidx = en_vocab.stoi["</s>"]

    train_len = 0
    val_len = 0
    for i in range(len(train_x)):
        train_len += train_x[i].size(1)
    for i in range(len(val_x)):
        val_len += val_x[i].size(1)

    model = AttnNetwork(len(de_vocab), len(en_vocab), dropout=args.dropout)
    #model.load_state_dict(torch.load("model_attn_SR.pth", map_location=lambda storage, loc: storage))

#    f = open('output.txt','w')
#    f.write("id,word\n")

#    i = 1
#    with open('source_test.txt', 'r') as fp:
#        for line in tqdm(fp):
#            line_vec = Variable(torch.Tensor([de_vocab.stoi[i ]for i in line.split()])).type_as(train_x[0])
#            final_pred = model.predict_beam(line_vec, startosidx, eosidx, len(en_vocab), beam_size=100)
#            f.write("{},".format(i))
#            for j in range(final_pred.size(0)):
#                beam = final_pred[j, :]
#                beam_join = escape("|".join(en_vocab.itos[j] for j in beam[1:4].tolist()))
#                print(beam_join)
#
#                f.write("{} ".format(beam_join))
#            f.write("\n")
#            #raise Exception()
#            i += 1
#    f.close()
#
#    raise Exception()

    if args.devid >= 0:
        model.cuda(args.devid)
    if args.optim == "Adam":
        optimizer = torch.optim.Adam(
            model.parameters(), lr = args.lr)
    elif args.optim == "Adadelta":
        optimizer = torch.optim.Adadelta(model.parameters(), rho=args.rho)
    elif args.optim == "SGD":
        optimizer = torch.optim.SGD(model.parameters(), lr=args.lr)
        scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[10, 11, 12, 13], gamma=0.5)
        #scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience=1, factor=args.lrd, threshold=1e-3)

    # We do not want to give the model credit for predicting padding symbols,
    #Find pad token
    padidx_en = en_vocab.stoi["<pad>"]
    criterion = nn.CrossEntropyLoss(size_average=False, ignore_index=padidx_en)

    print()
    print("TRAINING:")
    for i in range(args.epochs):
        scheduler.step()

        train_iter = zip(train_x, train_y)
        val_iter = zip(val_x, val_y)
        print("Epoch {}".format(i))
        train_loss = train(train_iter, model, criterion, optimizer, train_len)
        valid_loss, bleu = validate(val_iter, model, criterion, val_len, startosidx, eosidx, en_vocab)
        #scheduler.step(valid_loss)

        print("Training: {} Validation: {}".format(math.exp(train_loss), math.exp(valid_loss)))

    print()
    print("TESTING:")
    val_iter = zip(val_x, val_y)
    test_loss, bleu = validate(val_iter, model, criterion, val_len, startosidx, eosidx, en_vocab)
    print("Test: {}".format(math.exp(test_loss)))

    torch.save(model.state_dict(), 'model_attn_SR.pth')


# -*- coding:utf-8 -*-

import openpyxl
import datetime

class Data_Operat(object):
    def __init__(self):
        self.sys_all = None
        self.sys_other = None

    def create_Newsheet(self, filename, sheetname):
        wb = openpyxl.load_workbook(filename)
        for name in sheetname:
            wb.create_sheet(name)
        try:
            wb.remove_sheet(wb.get_sheet_by_name('Sheet'))
        except:
            pass
        return wb

    def get_Sheet(self, wb, name, title):
        ws = wb.get_sheet_by_name(name)
        ws.append(title)
        return ws

    def save_Excel(self, wb, filename):
        wb.save(filename)
        wb.close()

    def get_Data(self, rows):
        data = []
        for row in rows:
            data.append(row.value)
        return data

    def count_Dict(self, dict, key):
        if key not in dict.keys():
            dict[key] = 1
        else:
            dict[key] += 1
        return dict

    def get_Dict_data(self, ws, dict):
        data = []
        data_sort = []
        for key in dict.keys():
            data.append([key, dict[key]])
        for x in range(len(data)):
            if x == 0:
                data_sort.append(data[x])
                continue
            data_sort.append(data[x])
            for i in range(1, x+1):
                if int(data_sort[x+1-i][1]) > int(data_sort[x - i][1]):
                    a = data_sort[x-i]
                    data_sort[x-i] = data_sort[x+1-i]
                    data_sort[x+1-i] = a
        for x in range(len(data_sort)):
            ws.append(data_sort[x])
        return ws

    def system_Belong(self, ip, assetall):
        for all in assetall:
            if ip == all[0]:
                self.sys_all = all[1]
        return self.sys_all

    def data_Regular(self, response, record_type):
        test = 0
        if response != None:
            for type in record_type:
                result = type.findall(response)
                if len(result) != 0:
                    return False
        return True

    def rate_Count(self, time):
        time_ = []
        rate = {}
        wb_source = openpyxl.load_workbook("inputFile/" + time + "/IP_with_area.xlsx")
        wb_end = openpyxl.load_workbook("outputFile/" + time + u"/统计.xlsx")
        wb_end.create_sheet(u"IP(全)")
        ws_source = wb_source.get_sheet_by_name("Sheet")
        ws_end = wb_end.get_sheet_by_name(u"IP(全)")
        for i in range(2, 8):
            time_.append((datetime.datetime.now() - datetime.timedelta(days=i)).strftime('%Y%m%d'))
        ip_6day = []
        for t in time_:
            test = []
            wb = openpyxl.load_workbook("inputFile/" + t + "/IP_with_area.xlsx")
            ws = wb.get_sheet_by_name("Sheet")
            for y in list(ws.rows):
                test.append(y[0].value)
            ip_6day.append(test)
            wb.close()
        count = 0
        for x in list(ws_source.rows):
            x = list(x)
            if count <1:
                title = []
                for y in x:
                    title.append(y.value)
                title.append(u'频率')
                ws_end.append(title)
                count += 1
                continue
            rate[x[0].value] = 1
            data = []
            for y in x:
                data.append(y.value)
            for day in ip_6day:
                for ip in day:
                    if ip == x[0].value:
                        rate[x[0].value] += 1
                        break
            data.append(rate[x[0].value])
            ws_end.append(data)
        wb_end.save("outputFile/" + time + u"/统计.xlsx")
        wb_end.close()
        wb_source.close()

    def area_Mate(self,time, class_):
        title = [u'IP', u'地区', u'次数', u'频率']
        wb_ = openpyxl.load_workbook("outputFile/" + time + "/Top5.xlsx")
        wb = openpyxl.load_workbook("outputFile/" + time + u"/统计.xlsx")
        ws_source = wb.get_sheet_by_name(u"IP(全)")
        ws_class = wb_.get_sheet_by_name(class_)
        wb_.create_sheet('temp')
        ws_temp = wb_.get_sheet_by_name('temp')
        ws_temp.append(title)
        count = 0
        for x in list(ws_class.rows):
            x = list(x)
            if count < 1:
                count += 1
                continue
            for y in list(ws_source.rows):
                y = list(y)
                if x[0].value == y[0].value:
                    data = []
                    data.append(y[0].value)
                    if y[2].value != u'中国':
                        data.append(y[2].value)
                    else:
                        str = ''
                        for m in (4, 5, 6):
                            if y[m].value != 'NULL':
                                str += y[m].value
                        data.append(str)
                    data.append(x[1].value)
                    data.append(y[7].value)
                    ws_temp.append(data)
                    break
        wb_.remove(ws_class)
        ws_temp.title = class_
        wb_.save("outputFile/" + time + "/Top5.xlsx")
        wb.close()


def _exec_command(self, cmd, in_data=None, sudoable=True):
    ' run a command on the remote host '
    super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
    display.vvv('ESTABLISH SSH CONNECTION FOR USER: {0}'.format(self._play_context.remote_user), host=self._play_context.remote_addr)
    if ((not in_data) and sudoable):
        args = ('ssh', '-tt', self.host, cmd)
    else:
        args = ('ssh', self.host, cmd)
    cmd = self._build_command(*args)
    (returncode, stdout, stderr) = self._run(cmd, in_data, sudoable=sudoable)
    return (returncode, stdout, stderr)


""" Unit tests for the frontend """

import pytest
from streetwise import create_app, db

app = create_app()
app_context = app.app_context()

@pytest.fixture(scope="module")
def client():
    app.config['TESTING'] = True
    return app.test_client()

def test_api(client):
    resp = client.get('/')
    assert resp.status_code == 200


from typing import Dict, Tuple
from random import uniform
from math import pi

from genetic_framework.chromosome import Genotype
from ackley.util import DataType

class FloatGenotype(Genotype[float]):
    def __init__(self, custom_data: Dict = {}) -> None:
        super().__init__(custom_data)
        self.type: DataType = DataType.VARIABLE
        self._data: float = 0.0

    def initialize(self) -> None:
        lower_bound: float = self.custom_data['lower_bound']
        upper_bound: float = self.custom_data['upper_bound']
        step_size: float = self.custom_data['step_size']

        if self.type == DataType.VARIABLE:
            self._data = uniform(lower_bound, upper_bound)
        elif self.type == DataType.STEP_SIZE:
            self._data = step_size
        else:
            self._data = uniform(-pi, pi)

    @property
    def data(self) -> float:
        return self._data

    @data.setter
    def data(self, new_data: float) -> None:
        lower_bound: float = self.custom_data['lower_bound']
        upper_bound: float = self.custom_data['upper_bound']

        if self.type == DataType.VARIABLE and (new_data < lower_bound
                                               or new_data > upper_bound):
            raise ValueError(
                'Tried to set FloatGenotype data with ({}). Should be [{}, {}]'
                .format(new_data, lower_bound, upper_bound))

        self._data = new_data

    def __str__(self) -> str:
        return str(self.data)

    def __repr__(self) -> str:
        return self.__str__()

class FloatPairGenotype(Genotype[Tuple[float, float]]):
    def __init__(self, custom_data: Dict = {}) -> None:
        super().__init__(custom_data)
        self._data: Tuple[float, float] = (0.0, 0.0)

    def initialize(self) -> None:
        lower_bound: float = self.custom_data['lower_bound']
        upper_bound: float = self.custom_data['upper_bound']
        delta: float = self.custom_data['step_size']
        x: float = uniform(lower_bound, upper_bound)
        self._data = (x, delta)

    @property
    def data(self) -> Tuple[float, float]:
        return self._data

    @data.setter
    def data(self, new_data: Tuple[float, float]) -> None:
        lower_bound: float = self.custom_data['lower_bound']
        upper_bound: float = self.custom_data['upper_bound']

        if new_data[0] < lower_bound or new_data[0] > upper_bound:
            raise ValueError(
                'Tried to set FloatPairGenotype data with ({}). Should be [{}, {}]'
                .format(new_data[0], lower_bound, upper_bound))

        self._data = new_data

    def __str__(self) -> str:
        return str(self.data)

    def __repr__(self) -> str:
        return self.__str__()


# -*- coding: utf-8 -*-

from base import *

TEMPLATE_CSHARP_MANAGER = 'ConfigManagerConfigNameList.cs'
TEMPLATE_ITEM           = 'ConfigRows.cs'
TEMPLATE_SUB_ITEM       = 'ConfigRow.cs'

TEMPLATE_DIRECTORY = 'csharp_template'
WIRTE_DIRECTORY    = 'csharp'

CSHARP_UNKNOWN_TYPE = 'unknown'
CSHARP_INT_TYPE     = 'int'
CSHARP_FLOAT_TYPE   = 'float'
CSHARP_STRING_TYPE  = 'string'
CSHARP_DOUBLE_TYPE  = 'double'
CSHARP_BOOL_TYPE    = 'bool'
CSHARP_JSON_TYPE    = 'JSONArray'

LEFT_BRACE  = '{'
RIGHT_BRACE = '}'

CONFIG_MANAGER_FIELD_DECLARE = '\n\tConfigTable<{name}> {instance} = new ConfigTable<{name}>();'
CONFIG_MANAGER_PROPERTY_CLAUSE = '\n\tpublic ConfigTable<{name}> {property} {left} get {left} return {instance}; {right} {right}'
CONFIG_MANAGER_LOAD_CLAUSE = '\n\t\tLoadFromFile<{class_name}>("{table_name}");'

class CSharpGenerate(Base):

    _sub_item_template = ''

    def __init__(self):
        Base.__init__(self)
        self._make_dirs(WIRTE_DIRECTORY)

    def load_xls_file(self, xls_file):
        self._load_xls_file(xls_file)

    # 获取每次表的字段类型及字段名称
    def get_table_structure(self, sheet_name):
        table = self._try_get_sheet_by_name(sheet_name)
        column_names = table.row_values(TABLE_COLUMN_NAME_ROW_INDEX)
        column_types = table.row_values(TABLE_COLUMN_TYPE_ROW_INDEX)

        ret_json = []
        index = 0
        for column_index in range(table.ncols):
            if column_index == 0:
                index += 1
                continue

            column = {}

            column_name = column_names[column_index]
            if column_name == '':
                continue

            column_type = column_types[column_index]
            if column_type == '':
                continue

            code_type = CSHARP_UNKNOWN_TYPE;
            if column_type == COLUMN_INT_TYPE:
                code_type = CSHARP_INT_TYPE
            elif column_type == COLUMN_FLOAT_TYPE:
                code_type = CSHARP_FLOAT_TYPE
            elif column_type == COLUMN_DOUBLE_TYPE:
                code_type = CSHARP_DOUBLE_TYPE
            elif column_type == COLUMN_BOOL_TYPE:
                code_type = CSHARP_BOOL_TYPE
            elif column_type == COLUMN_STRING_TYPE:
                code_type = CSHARP_STRING_TYPE
            elif column_type == COLUMN_JSON_TYPE:
                code_type = CSHARP_JSON_TYPE

            if code_type == CSHARP_UNKNOWN_TYPE:
                continue

            column['type'] = code_type
            column['title'] = column_name
            column['index'] = index
            ret_json.append(column)

            index += 1
        return ret_json

    # 获取Config##Item中字段的声明
    def get_config_item_filed(self, column_type, column_title):
        return str.format('\n\tpublic {} {} {} get; private set; {}', column_type, self.change_to_code_name(column_title), '{', '}')

    # 获取Config##Item.Init中的分配语句
    def get_config_item_assigment(self, column_type, column_title, column_index):
        assign_clause = str.format('\n\t\t{} = node[{}]', self.change_to_code_name(column_title), column_index)
        if column_type == CSHARP_INT_TYPE:
            assign_clause += ".AsInt;"
        elif column_type == CSHARP_FLOAT_TYPE:
            assign_clause += ".AsFloat;"
        elif column_type == CSHARP_DOUBLE_TYPE:
            assign_clause += ".AsDouble;"
        elif column_type == CSHARP_BOOL_TYPE:
            assign_clause += ".AsBool;"
        elif column_type == CSHARP_JSON_TYPE:
            assign_clause += " as JSONArray;"
        else:
            assign_clause += ";"
        return assign_clause

    # 获取Config##Item类型名
    def get_config_item_class_name(self, output_name):
        return str.format('Config{}Row', self.change_to_code_name(output_name))

    def get_config_sub_item_template(self):
        if self._sub_item_template == '':
            self._sub_item_template = self.try_open_file(TEMPLATE_SUB_ITEM)
        return self._sub_item_template

    # 生成一个ConfigXXXItem
    def get_config_sub_item(self, output_name, column_array):
        fileds = ''
        assigments = ''
        for column in column_array:
            fileds += self.get_config_item_filed(column['type'], column['title'])
            assigments += self.get_config_item_assigment(column['type'], column['title'], column['index'])
        sub_item = self.get_config_sub_item_template()
        return sub_item.format(config_sub_class = self.get_config_item_class_name(output_name),
            config_fields = fileds, config_fields_assigment = assigments, left = LEFT_BRACE, right = RIGHT_BRACE)

    # 获取ConfigManager中ConfigTable<T>的变量名
    def get_config_manager_field_name(self, output_name):
        return str.format('m_Config{}Table', self.change_to_code_name(output_name))

    # 获取ConfigManager的属性名
    def get_config_manager_property_name(self, output_name):
        return self.change_to_code_name(output_name)

    # 获取ConfigManager字段声明语句
    def get_config_manager_file_clause(self, output_name):
        config_class_name = self.get_config_item_class_name(output_name)
        config_class_instance = self.get_config_manager_field_name(output_name)
        return CONFIG_MANAGER_FIELD_DECLARE.format(name = config_class_name, instance = config_class_instance);

    # 获取ConfigManager属性声明语句
    def get_config_manger_propery_clause(self, output_name):
        config_property = self.get_config_manager_property_name(output_name)
        config_class_name = self.get_config_item_class_name(output_name)
        config_class_instance = self.get_config_manager_field_name(output_name)
        return CONFIG_MANAGER_PROPERTY_CLAUSE.format(name = config_class_name, instance = config_class_instance,
            property = config_property, left = LEFT_BRACE, right = RIGHT_BRACE)

    # 获取ConfigManager.Load中的JSON文件加载语句
    def get_config_manager_load_clause(self, output_name):
        config_class_name = self.get_config_item_class_name(output_name)
        return CONFIG_MANAGER_LOAD_CLAUSE.format(class_name = config_class_name, table_name = output_name)

    # 生成ConfigManager所需的field, proerty, load
    def parse_config_manager(self, output_name_array):
        filed_clauses = ''
        property_clauses = ''
        load_clauses = ''
        for output_name in output_name_array:
            filed_clauses += self.get_config_manager_file_clause(output_name)
            property_clauses += self.get_config_manger_propery_clause(output_name)
            load_clauses += self.get_config_manager_load_clause(output_name)
        return filed_clauses, property_clauses, load_clauses

    # 判断文件是否存在
    def template_directory_exists(self):
        return self._directory_exists(os.path.abspath(TEMPLATE_DIRECTORY))

    # 打开文件
    def try_open_file(self, file_name):
        if self.template_directory_exists():
            file_path = os.path.abspath(os.path.join(TEMPLATE_DIRECTORY, file_name))
            if os.path.exists(file_path) and os.path.isfile(file_path):
                f = file(file_path, 'r')
                value = f.read()
                f.close()
                return value
            else:
                self._error(str.format('"{}"文件不存在', file_name))
                sys.exit()
        else:
            self._error(str.format('"{}"文件夹不存在', TEMPLATE_DIRECTORY))
            sys.exit()

    # ========> 外部调用接口
    # 返回，ConfigManager(fiels, properties, loads), ConfigItems
    def get_config_info(self):
        config_items = ''
        config_name_list = ''
        # config_name_array = []
        for row in self._output_config_table:
            column_array = self.get_table_structure(row[CONFIG_SHEET_NAME_COLUMN_INDEX])
            output_name = row[CONFIG_OUTPUT_NAME_COLUMN_INDEX]

            if len(config_name_list) > 0:
                config_name_list += ", "
            config_name_list += str.format('"{}"', self.change_to_code_name(output_name))
            # config_name_array.append(output_name)

            config_items += self.get_config_sub_item(output_name, column_array)
            config_items += '\n\n'

        return config_name_list, config_items

    # ========> 外部调用接口
    # 生成ConfigManager.cs文件
    def export_config_manager(self, config_name_list):
        config_manager = self.try_open_file(TEMPLATE_CSHARP_MANAGER)
        config_manager = config_manager.format(config_name_list = config_name_list, left = LEFT_BRACE, right = RIGHT_BRACE)
        self._write(WIRTE_DIRECTORY, TEMPLATE_CSHARP_MANAGER, config_manager)

    # ========> 外部调用接口
    # 生成ConfigItem.cs文件
    def export_config_item(self, config_items):
        config_item = self.try_open_file(TEMPLATE_ITEM)
        config_item = config_item.format(config_items = config_items, left = LEFT_BRACE, right = RIGHT_BRACE)
        self._write(WIRTE_DIRECTORY, TEMPLATE_ITEM, config_item)


import socket

def log(*args, **kwargs):
    print('\033[1;35;0m log：', *args, **kwargs, end='')
    print('\033[0m')

def response_for_path(path):
    return b'HTTP/1.1 404 NOT FOUND\r\n\r\n
NOT FOUND
'

def run(host='127.0.0.1', port=3000):
    with socket.socket() as s:
        s.bind((host, port))
        # 无限循环来处理请求
        log(s)
        log('address:http://{}:{}'.format(host, port))
        while True:
            s.listen(5)
            connection, address = s.accept()
            request = connection.recv(1024)
            log(request)
            try:
                path = request.split()[1]
                connection.sendall(response_for_path(path))
            except Exception as e:
                print(str(e))
            connection.close()

if __name__ == '__main__':
    run()