import tkinter as tk
from Game import Game
from image_objects import image_objects
from tkinter import messagebox
from tkinter import ttk
from datetime import datetime

class App:

    # Creates a Frame for the application and populates the GUI...
    def __init__(self, root):
        # Creating game class
        self.game = Game()
        self.player_check = 0
        self.root = root

        # creating some menu items
        menubar = tk.Menu()
        menubar.add_command(label="Quit", command=self.root.destroy)
        menubar.add_command(label="About", command=self.show_about)
        self.root.config(menu=menubar)

        # Create two frames owned by the window root.
        # In order to use multiple layout managers, the frames
        # cannot share a parent frame. Here both frames are owned
        # by a top level instance root.
        self.frame1 = tk.Frame(self.root, width=900, height=380, bg='#ADD8E6', borderwidth=2)
        self.frame1.grid_propagate(False)  # Prevents resizing
        self.frame2 = tk.Frame(self.root, width=900, height=220, bg='WHITE', borderwidth=2)
        self.frame2.grid_propagate(False)  # Prevents resizing
        self.frame3 = tk.Frame(self.root, width=900, height=150, bg='LIGHT GREY', borderwidth=2)
        self.frame3.grid_propagate(False)  # Prevents resizing
        # This packs both frames into the root window...
        self.frame1.grid(row=0, column=0)
        self.frame2.grid(row=1, column=0)
        self.frame3.grid(row=3, column=0)

        # Now add some useful widgets...
        self.text_area1 = tk.Label(self.frame2, text='')
        self.text_area1.place(x=450, y=100, anchor="center")
        # self.cmd_area = tk.Entry(self.frame3, text='')
        # self.cmd_area.place(x=450, y=10, anchor="center")

        # Initialising images objects
        self.ioj = image_objects()
        self.button_list = {}
        self.drop_list = {}

        # Initialising GUI elements like buttons, gates etc.
        self.build_GUI()

        # Opening the user activity log file
        timestamp = datetime.now().strftime("%d_%m_%y %H%M%S")
        self.log = open('./logs/log_'+str(timestamp)+'.txt', 'w')
        lines = f"Timestamp,Command,Current_Room,Player_Inventory"
        self.log.write(lines)

    def build_GUI(self):
        """
        This function initialises various UI elements which are to be embedded into the game sreen
        :return:
        """
        self.text_area1.configure(text="Select Player: 'Male' or 'Female'")

        # Creating buttons for different functions
        # Movement buttons
        self.move_north = tk.Button(self.frame3, text='Go North', fg='white', bg='#00008B',
                                    command=lambda: self.do_command("Go North"))
        self.move_south = tk.Button(self.frame3, text='Go South', fg='white', bg='#00008B',
                                    command=lambda: self.do_command("Go South"))
        self.move_east = tk.Button(self.frame3, text=' Go East ', fg='white', bg='#00008B',
                                   command=lambda: self.do_command("Go East"))
        self.move_west = tk.Button(self.frame3, text=' Go West ', fg='white', bg='#00008B',
                                   command=lambda: self.do_command("Go West"))
        self.move_up = tk.Button(self.frame3, text='   Go Upstairs  ', fg='white', bg='#00008B',
                                 command=lambda: self.do_command("Go Upstairs"))
        self.move_down = tk.Button(self.frame3, text='Go Downstairs', fg='white', bg='#00008B',
                                   command=lambda: self.do_command("Go Downstairs"))

        # Help button
        self.help = tk.Button(self.frame3, text='Help!', fg='white', bg='#00008B',
                              command=lambda: self.do_command("help"))
        # Quit Button
        self.quit = tk.Button(self.frame3, text='  Quit', fg='white', bg='#00008B',
                              command=self.root.destroy)

        # Player selection buttons
        self.male_player = tk.Button(self.frame3, text='Male   â™‚', fg='white', bg='#00008B',
                                     command=lambda: self.do_command("Male"))
        self.male_player.place(x=380, y=10)
        self.female_player = tk.Button(self.frame3, text='Female â™€', fg='white', bg='#AA336A',
                                       command=lambda: self.do_command("Female"))
        self.female_player.place(x=440, y=10)

        # Inventory buttons
        self.inventory_options = tk.Button(self.frame3, text='Inventory', fg='white', bg='#00008B',
                                           command=lambda: self.show_inventory_options())
        self.pick_items = tk.Button(self.frame3, text='Pick Items', fg='white', bg='#00008B',
                                           command=lambda: self.do_command("Pick items"))
        self.drop_items = tk.Button(self.frame3, text='Drop/View Items', fg='white', bg='#00008B',
                                    command=lambda: self.do_command("Drop items"))
        self.view_items = tk.Button(self.frame3, text='View Items', fg='white', bg='#00008B',
                                    command=lambda: self.do_command("View items"))
        self.hide = tk.Button(self.frame3, text='     Hide     ', fg='white', bg='#00008B',
                                    command=lambda: self.hide_inventory_options())

        # Activity buttons
        self.use_knife = tk.Button(self.frame3, text='Use Knife', fg='white', bg='#00008B',
                                    command=lambda: self.do_command("Use Knife"))
        self.use_gun = tk.Button(self.frame3, text='Use Gun', fg='white', bg='#00008B',
                                   command=lambda: self.do_command("Use gun"))
        self.use_automaticgun = tk.Button(self.frame3, text='Use Rifle', fg='white', bg='#00008B',
                                   command=lambda: self.do_command("Use automaticgun"))
        self.unlock_heli = tk.Button(self.frame3, text='Unlock Helicopter', fg='white', bg='#00008B',
                                          command=lambda: self.do_command("Unlock Helicopter"))

        # Health Bar
        # Progress bar widget
        self.health_status = ttk.Progressbar(self.frame3, orient="horizontal", length=100, mode='determinate', value=100)
        self.health_label = tk.Label(self.frame3, text="Player Health", pady=0)

    def room_ui(self, frame, room_loc, width, height, room=None, door_details=None):
        """
        method to create UI for different rooms
        :return:
        """
        # create styling
        style1 = ttk.Style()
        # style1.configure('TSeparator', background='black' )
        style1.configure('TSeparator', background='black')

        # Unpacking room location
        x, y = room_loc

        # Creating walls for room
        # North wall
        ttk.Separator(frame, orient="horizontal", style='TSeparator', class_=ttk.Separator, takefocus=1,
                      cursor='cross').place(x=x, y=y, width=width)
        # South wall
        ttk.Separator(frame, orient="horizontal", style='TSeparator', class_=ttk.Separator, takefocus=1,
                      cursor='plus').place(x=x, y=y+height, width=width)
        # East wall
        ttk.Separator(frame, orient="vertical", style='TSeparator', class_=ttk.Separator, takefocus=1,
                      cursor='plus').place(x=x+width, y=y, height=height)
        # West wall
        ttk.Separator(frame, orient="vertical", style='TSeparator', class_=ttk.Separator, takefocus=1,
                      cursor='plus').place(x=x, y=y, height=height)

        # Placing items in room
        if len(room.itemsInRoom) > 0:
            locs = self.ioj.item_locs((x, y), width, height)[:(len(room.itemsInRoom)+1)]
            items_to_place = [item.__class__.__name__ for item in room.itemsInRoom ]
            i=0
            for item_image in items_to_place:
                command = "Pick " + item_image
                if item_image == "Keys":
                    item_image = item_image+"_"+room.itemsInRoom[0].keyOpens
                # Saving item objects as dictionary
                self.button_list[item_image] = tk.Button(frame, image=self.ioj.item_dict[item_image], borderwidth=0,
                                                         state="disabled", command=lambda command=command: self.do_command(command))
                self.button_list[item_image].photo = self.ioj.item_dict[item_image]
                self.button_list[item_image].place(x=locs[i][0], y=locs[i][1])
                i += 1

        # Placing doors if any
        if door_details is not None:
            for door in door_details:
                if room.isLocked:
                    self.doorButton = tk.Button(self.frame1, text="|        ðŸ”’        |" if door["dir"] == "north" or door["dir"] == "south" else "__\n\nðŸ”’\n\n__",
                                                bg="black", fg="white", command=lambda: self.do_command("Unlock Door"))
                    self.doorButton.place(x=door["loc"][0], y=door["loc"][1])
                else:
                    # Create a Label Widget to display the text or Image
                    img=self.ioj.item_dict["door_north"] if door["dir"] == "north" else (self.ioj.item_dict["door_south"] if door["dir"] == "south" else
                                                                        (self.ioj.item_dict["door_east"] if door["dir"] == "east" else self.ioj.item_dict["door_west"]))
                    label = tk.Label(frame, image=img, borderwidth=0)
                    label.photo = img
                    label.place(x=door["loc"][0], y=door["loc"][1])

    def destroy_rooms(self):
        """
        This function is used to destroy the UI in order to update the visuals.
        :return:
        """
        for widget in self.frame1.winfo_children():
            widget.destroy()

    def create_room_UI(self, room):
        """
        This method creates the whole floor layout based on the floor attribute of the current room received as the arguments.
        :param room: current room location based on which floor layout is decided
        :return: None
        """
        self.destroy_rooms()  # destroy rooms to update

        # Creating rooms layout based on floor
        if room.level == "Basement":
            self.room_ui(self.frame1, room_loc=(0, 200), width=450, height=170, room=self.game.experimentLab)  # Experiment Lab room
            self.room_ui(self.frame1, room_loc=(450, 0), width=440, height=370, room=self.game.lobbyBasement)  # Lobby Basement room
            self.room_ui(self.frame1, room_loc=(800, 150), width=90, height=120, room=self.game.staircaseBasement,
                         door_details=[{"dir": "west", "loc": (780, 175)}])  # Staircase room
            self.room_ui(self.frame1, room_loc=(0, 0), width=450, height=200, room=self.game.containmentArea,
                         door_details=[{"dir": "south", "loc": (200, 195)},
                                       {"dir": "east", "loc": (445, 70)}])  # Containment Lab room
        elif room.level == "Ground":
            self.room_ui(self.frame1, room_loc=(450, 170), width=440, height=90, room=self.game.corridorGround)  # corridor room
            self.room_ui(self.frame1, room_loc=(0, 0), width=450, height=260, room=self.game.lobbyGround,
                         door_details=[{"dir": "east", "loc": (445, 182)}])  # Lobby Ground floor
            self.room_ui(self.frame1, room_loc=(0, 0), width=100, height=100, room=self.game.staircaseGround2,
                         door_details=[{"dir": "east", "loc": (95, 15)}])  # Staircase 2 room
            self.room_ui(self.frame1, room_loc=(0, 260), width=890, height=110, room=self.game.cateringHall,
                         door_details=[{"dir": "north", "loc": (560, 240)}])  # Kitchen/Common room
            self.room_ui(self.frame1, room_loc=(450, 0), width=440, height=170, room=self.game.securityRoom,
                         door_details=[{"dir": "west", "loc": (430, 60)},
                                       {"dir": "south", "loc": (660, 160)}])  # Security room
            self.room_ui(self.frame1, room_loc=(800, 170), width=90, height=90, room=self.game.staircaseGround1,
                         door_details=[{"dir": "west", "loc": (780, 180)}])  # staircase 1 room
        elif room.level == "First":
            self.room_ui(self.frame1, room_loc=(100, 0), width=400, height=150, room=self.game.corridorFirst)  # corridor room
            self.room_ui(self.frame1, room_loc=(0, 0), width=100, height=150, room=self.game.staircaseFirst1,
                         door_details=[{"dir": "east", "loc": (95, 40)}])  # Staircase 1 room
            self.room_ui(self.frame1, room_loc=(500, 0), width=390, height=150, room=self.game.changeRoom,
                         door_details=[{"dir": "west", "loc": (480, 40)},
                                       {"dir": "south", "loc": (670, 147)}])  # Change room
            self.room_ui(self.frame1, room_loc=(0, 150), width=390, height=220, room=self.game.adminOffice,
                         door_details=[{"dir": "north", "loc": (160, 140)},
                                       {"dir": "east", "loc": (385, 230)}])  # Admin room
            self.room_ui(self.frame1, room_loc=(390, 150), width=500, height=220, room=self.game.medicalRoom)  # Medical room
            self.room_ui(self.frame1, room_loc=(730, 290), width=160, height=80, room=self.game.staircaseFirst2,
                         door_details=[{"dir": "north", "loc": (780, 268)}])  # Staircase 2 room
        elif room.level == "Roof":
            self.room_ui(self.frame1, room_loc=(450, 0), width=440, height=370, room=self.game.openRoof,)  # Open Area
            self.room_ui(self.frame1, room_loc=(0, 0), width=450, height=370, room=self.game.helipad,
                         door_details=[{"dir": "east", "loc": (445, 180)}])  # Helipad
            self.room_ui(self.frame1, room_loc=(740, 270), width=150, height=100, room=self.game.staircaseRoof,
                         door_details=[{"dir": "north", "loc": (780, 248)}])  # Staircase roof
            self.room_ui(self.frame1, room_loc=(640, 0), width=250, height=130, room=self.game.maintenanceRoom,
                         door_details=[{"dir": "south", "loc": (740, 127)}])  # Maintenance room

    def move_character(self, pos):
        """
        Helps to place the player at correct locations depending on the room they are in
        :param pos: the position in pixels
        :return:
        """
        # creating the image and placing at appropriate location
        character_img = self.ioj.item_dict[self.game.player.username]
        label = tk.Label(self.frame1, image=character_img, borderwidth=0)
        label.photo = character_img
        label.place(x=pos[0], y=pos[1])

    def hide_inventory_options(self):
        """
        method used to hide inventory options (pick, drop etc)
        :return:
        """
        self.inventory_options.place(x=77, y=76)
        self.pick_items.place_forget()
        self.drop_items.place_forget()
        self.view_items.place_forget()
        self.hide.place_forget()

    def show_inventory_options(self):
        """
        method to show inventory options
        :return:
        """
        self.inventory_options.place_forget()
        self.pick_items.place(x=10, y=77)
        self.drop_items.place(x=81, y=77)
        # self.view_items.place(x=156, y=77)
        self.hide.place(x=186, y=77)

    def game_over(self, force=False):
        """
        Method checks the health and terminates the game is health is less than or equal to 0.
        :param force: if the game should terminate due to some other reasons aside from low health
        :return:
        """
        if self.game.player.health <= 0 or force:
            self.destroy_rooms()
            img = self.ioj.item_dict["gameover"]
            label = tk.Label(self.frame1, image=img, borderwidth=0)
            label.photo = img
            label.place(x=300, y=50)
            self.text_area1.configure(text="YOU DIED.....GAME OVER!!!")
            self.root.after(3000, self.root.destroy)

    def do_command(self, command=None):
        """
        method to execute the commands given by the button press
        :param command:
        :return:
        """
        if command is None:
            command = self.cmd_area.get()  # Returns a 2-tuple
        try:
            self.record_commands(command)
            self.process_command(command)
        except Exception as e:
            print(e)
        print("command: ", command)

    def record_commands(self, command):
        """
        Method to record the user activity log every time a user plays the game
        :param command:
        :return:
        """
        try:
            timestamp = datetime.now().strftime("%d_%m_%y %H%M%S")
            # writing some important information into the log file
            lines = f"\n{timestamp},{command},{self.game.current_room},{self.game.player.inventory if self.game.player is not None else 'No Item'}"
            self.log.write(lines)
        except ValueError as msg:
            print(msg)
        except AttributeError as msg:
            print(msg)
        except:
            print("That should not have happened..!!")

    def get_command_string(self, input_line):
        """
            Fetches a command (borrowed from old TextUI).
        :return: a 2-tuple of the form (command_word, second_word)
        """
        word1 = None
        word2 = None
        if input_line != "":
            all_words = input_line.split()
            word1 = all_words[0]
            if len(all_words) > 1:
                word2 = all_words[1]
            else:
                word2 = None
            # Just ignore any other words
        return word1, word2

    def process_command(self, command):
        """
        This method is used to process a command from the user to reflect in the ui.
        :param: command: a 2-tuple of the form (command_word, second_word)
        """

        # Checking for player health and decide survival
        if self.player_check != 0:
            self.game_over()

        command_word, second_word = self.get_command_string(command)
        if command_word is not None:
            command_word = command_word.lower()
            if second_word is not None:
                second_word = second_word.lower()
            # Whole If-else ladde takes care of different types of commands that the user can give
            if command_word == "pick" and self.player_check == 1:
                if second_word == "items":
                    if len(self.game.current_room.itemsInRoom) > 0:
                        # displaying available items
                        textLines = f"Choose item to pick:\n" \
                                    f"{['Pick ' + type(item).__name__ for item in self.game.current_room.itemsInRoom]}"
                        self.text_area1.configure(text=textLines)

                        # Changing button state from disabled to active
                        for thing in [type(item).__name__ for item in self.game.current_room.itemsInRoom]:
                            if thing == "Keys":
                                thing = thing + "_" + self.game.current_room.itemsInRoom[0].keyOpens
                            self.button_list[thing].configure(state="normal")
                    else:
                        self.text_area1.configure(text="!!..No Items to pick..!!\n\n" + self.game.story()[0])
                else:
                    # picking items here
                    item = [item for item in self.game.current_room.itemsInRoom if
                            type(item).__name__.lower() == second_word]
                    if len(item) == 0:
                        self.text_area1.configure(text="Don't know what you mean..!!\n\n" + self.game.story()[0])
                    else:
                        check = self.game.player.pickItems(item[0])
                        if check:
                            thing = type(item[0]).__name__

                            # Removing items from Room in UI
                            if thing == "Keys":
                                thing = thing + "_" + self.game.current_room.itemsInRoom[0].keyOpens
                            self.button_list[thing].place_forget()
                            self.game.current_room.remove_item(item[0])
                            self.text_area1.configure(text="Item Picked..!!\n\n" + self.game.story()[0])
                        elif check is False:
                            self.text_area1.configure(text="Max load exceeded. Item can't be picked..!!\nDrop some"
                                                           "items.\n\n" + self.game.story()[0])
            elif command_word == "drop" and self.player_check == 1:
                if second_word == "items":
                    if len(self.game.player.inventory) > 0:
                        # displaying items
                        textLines = f"Choose item to drop:\n" \
                                    f"{['Drop ' + type(item).__name__ for item in self.game.player.inventory]}"
                        self.text_area1.configure(text=textLines)

                        items_to_drop = [item.__class__.__name__ for item in self.game.player.inventory]
                        i = 0
                        # Showing items in inventory which can be dropped
                        for item_image in items_to_drop:
                            command = "Drop " + item_image
                            if item_image == "Keys":
                                item_image = item_image + "_" + self.game.player.inventory[i].keyOpens
                            self.drop_list[item_image] = tk.Button(self.frame3, image=self.ioj.item_dict[item_image],
                                                                     borderwidth=0,
                                                                     command=lambda command=command: self.do_command(command))
                            self.drop_list[item_image].photo = self.ioj.item_dict[item_image]
                            self.drop_list[item_image].place(x=290+i*60, y=90)
                            i += 1
                    else:
                        self.text_area1.configure(text="!!..No Items to drop..!!\n\n" + self.game.story()[0])
                else:
                    # dropping items here
                    item = [item for item in self.game.player.inventory if
                            type(item).__name__.lower() == second_word]
                    if len(item) == 0:
                        self.text_area1.configure(text="Don't know what you mean..!!\n\n" + self.game.story()[0])
                    else:
                        check = self.game.player.dropItems(item[0])
                        if check:
                            self.game.current_room.add_item(item[0])

                            # Adding the items back to room
                            thing = type(item[0]).__name__
                            if thing == "Keys":
                                thing = thing + "_" + item[0].keyOpens
                            self.drop_list[thing].place_forget()

                            # placing rooms
                            self.create_room_UI(self.game.current_room)

                            # moving character
                            self.move_character(self.game.story()[1])

                            self.text_area1.configure(text="Item Dropped..!!\n\n" + self.game.story()[0])
                        elif check is False:
                            self.text_area1.configure(text="!!..No Items to drop..!!\n\n" + self.game.story()[0])
            elif command_word == "view" and self.player_check == 1:
                if len(self.game.player.inventory) == 0:
                    textLines = f"!!..Inventory Empty..!!\n\n"
                else:
                    textLines = self.game.player.viewItems()
                    i = 0
                self.text_area1.configure(text=textLines + "\n\n" + self.game.story()[0])
            elif command_word == "help" and self.player_check == 1:
                self.text_area1.configure(text=self.game.print_help())
            elif command_word == "go" and self.player_check == 1:
                textLines = self.game.do_go_command(second_word)
                self.text_area1.configure(text=textLines[0])

                self.health_status['value'] = self.game.player.health

                # placing rooms
                self.create_room_UI(self.game.current_room)

                # moving character
                self.move_character(textLines[1])

                # Placing zombies and the 'use' buttons as per games progress
                if self.game.current_room.roomName == "corridorGround" and self.game.zombie1alive:
                    self.use_knife.place(x=500, y=27)
                    self.zombie1 = tk.Label(self.frame1, image=self.ioj.item_dict["zombie1"], borderwidth=0)
                    self.zombie1.photo = self.ioj.item_dict["zombie1"]
                    self.zombie1.place(x=630, y=190)
                elif self.game.current_room.roomName == "helipad" and self.game.zombieMainalive:
                    self.use_automaticgun.place(x=500, y=27)
                    self.zombieMain = tk.Label(self.frame1, image=self.ioj.item_dict["zombieMain"], borderwidth=0)
                    self.zombieMain.photo = self.ioj.item_dict["zombieMain"]
                    self.zombieMain.place(x=300, y=275)
                elif "Unlock Helicopter" in textLines[0]:
                    self.unlock_heli.place(x=500, y=27)

                if "GAME OVER" in textLines[0]:
                    self.root.after(4000, self.root.destroy)
            elif (command_word == "male" or command_word == "female") and self.player_check == 0:
                # creating some ui elements after user selects the player
                self.game.create_player(command_word)
                self.text_area1.configure(text=self.game.print_welcome())
                self.player_check = 1
                self.male_player.place_forget()
                self.female_player.place_forget()
                self.move_north.place(x=77, y=10)
                self.move_south.place(x=77, y=43)
                self.move_east.place(x=142, y=27)
                self.move_west.place(x=10, y=27)
                self.move_up.place(x=210, y=10)
                self.move_down.place(x=210, y=43)
                self.help.place(x=850, y=10)
                self.quit.place(x=850, y=42)
                self.health_status.place(x=790,y=90)
                self.health_label.place(x=792,y=115)
                self.inventory_options.place(x=77, y=76)
                # placing Basement rooms
                self.create_room_UI(self.game.current_room)
                # placing character
                self.move_character((200, 250))
            elif command_word == "use" and self.player_check == 1:
                if second_word == "knife":
                    textLines = self.game.knife1.cut()
                    if self.game.zombie1alive:
                        self.game.zombie1alive = False
                        self.text_area1.configure(
                            text=textLines + "\n" + "OH Damn, that zombie is dead...again !!" + "\n\n" + self.game.story()[0])
                        self.zombie1.destroy()
                    else:
                        self.text_area1.configure(
                            text=textLines + "\n" + "No Zombies here, you're safe!!" + "\n\n" + self.game.story()[0])
                    self.use_knife.place_forget()
                elif second_word == "gun":
                    status, textLines = self.game.pistol.shoot()
                    if status:
                        if self.game.zombie2alive:
                            self.game.zombie2alive = False
                            self.text_area1.configure(
                                text=textLines + "\n" + "OH Damn, that zombie is dead...again !!" + "\n\n" + self.game.story()[0])
                            self.zombie2.destroy()
                        else:
                            self.text_area1.configure(
                                text=textLines + "\n" + "No Zombies here, you're safe!!" + "\n\n" + self.game.story()[0])
                        self.use_gun.place_forget()
                elif second_word == "automaticgun":
                    status, textLines = self.game.burstgun.shoot()
                    if status:
                        if self.game.zombieMainalive:
                            self.game.zombieMainalive = False
                            self.text_area1.configure(
                                text=textLines + "\n" + "OH Damn, that zombie is dead...again !!" + "\n\n" + self.game.story()[0])
                            self.zombieMain.destroy()
                        else:
                            self.text_area1.configure(
                                text=textLines + "\n" + "No Zombies here, you're safe!!" + "\n\n" + self.game.story()[0])
                        self.final_win = tk.Button(self.frame3, text="Unlock Helicopter", fg='white', bg='#00008B',
                                                   command=lambda: self.do_command("Unlock Helicopter"))
                        self.final_win.place(x=500, y=27)
                        self.use_automaticgun.place_forget()
            elif command_word == "unlock" and self.player_check == 1:
                keys = [item for item in self.game.player.inventory if item.__class__.__name__ == "Keys"]
                self.text_area1.configure(text=f"Trying keys...!")
                if second_word == "door":
                    if len(keys) > 0:
                        for i in keys:
                            opened = i.unlock_door(self.game.next_room_locked)
                            if opened:
                                self.game.next_room_locked.isLocked = False
                                self.game.current_room = self.game.next_room_locked
                                self.text_area1.configure(
                                    text=f"Door is open. You may proceed further.\n\n" + self.game.story()[0])
                                # placing Basement rooms
                                self.create_room_UI(self.game.current_room)
                                # placing character
                                self.move_character(self.game.story()[1])
                                if self.game.current_room.roomName == "adminOffice" and self.game.zombie2alive:
                                    self.use_gun.place(x=500, y=27)
                                    self.zombie2 = tk.Label(self.frame1, image=self.ioj.item_dict["zombie2"], borderwidth=0)
                                    self.zombie2.photo = self.ioj.item_dict["zombie2"]
                                    self.zombie2.place(x=150, y=290)
                                break
                        if not opened:
                            self.text_area1.configure(text="Sorry no keys work. Please get the correct key..!!")
                    else:
                        self.text_area1.configure(text="No Keys in inventory..!!")
                elif second_word == "helicopter":
                    if len(keys) > 0:
                        for i in keys:
                            opened = i.unlock_door(self.game.helicopter)
                            if opened:
                                self.game.helicopter.isLocked = False
                                self.text_area1.configure(
                                    text=f"Door is open. You may proceed further.\n\n" + self.game.helicopter.fly())
                                self.destroy_rooms()
                                img = self.ioj.item_dict["winner"]
                                label = tk.Label(self.frame1, image=img, borderwidth=0)
                                label.photo = img
                                label.place(x=300, y=50)
                                self.log.close()
                                self.root.after(3000, self.root.destroy)
                                break
                        if not opened:
                            self.text_area1.configure(text="Sorry no keys work. Please get the correct key..!!")
                    else:
                        self.text_area1.configure(text="No Keys in inventory..!!")
            else:
                if self.player_check == 1:
                    # Handling Unknown commands...
                    self.text_area1.configure(
                        text=f"Don't know what you mean. Please choose correct option.\n\n{self.game.print_help()}")
                else:
                    self.text_area1.configure(
                        text=f"Don't know what you mean. Please choose correct option.\n\nSelect Player: 'Male' or 'Female'")

    def show_about(self):
        """
        method show about information as a messagebox
        :return:
        """
        msg = f"'Stranded in Apocalypse' a call from distant future.\n\nThere has been a global zombie break-out due to" \
              f" some malfunctioned military experiments. Whole world is in chaos. You are the last beacon of hope. You have to save the humanity by" \
              f" delivering an experimental child to a secret lab at other end of the city. Whole infrastructure has collapsed and you are" \
              f" humanity's last hope. Scientists at the lab are waiting for you to bring the child so that they can manufacture a vaccine.\n\n\
                Developed By: Kshitij Pathak"
        messagebox.showinfo("**Stranded in Apocalypse**", msg)

def main():
    win = tk.Tk()  # Create a window
    win.title("**Stranded in Apocalypse**")  # Set window title
    win.geometry("900x750")  # Set window size
    win.resizable(False, False)  # Both x and y dimensions...

    # Create the GUI as a Frame and attach it to the window...
    myApp = App(win)

    # Call the GUI mainloop...
    win.mainloop()

if __name__ == "__main__":
    main()


import json
import pandas as pd
from re import sub
import ast
storage_client = storage.Client()

bucket = storage_client.get_bucket("intern_cicle")
input_file_path = "scraping_result"
output_file_path = "cleaned_data"

blob = bucket.blob(input_file_path)
blob.download_to_filename('/tmp/relevant_play_store_reviews.csv')

df1 = pd.read_csv('/tmp/relevant_play_store_reviews.csv')

rename_dict = {'com.Slack':'slack',
    'com.microsoft.teams':'microsoft teams',
    'com.asana.app':'asana',
    'com.basecamp.bc3':'basecamp',
    'com.trello':'trello',
    'com.atlassian.android.jira.core':'jira cloud',
    'com.monday.monday':'monday.com',
    'com.wrike':'wrike',
    'com.smartsheet.android':'smartsheet',
    'com.zoho.projects':'zoho projects',
    'io.quire.app':'quire',
    'com.todoist':'todoist',
    'com.meisterlabs.meistertask.native':'meistertask',
    'com.proofhub':'proofhub'}
df1['appId']=df1['appId'].replace(rename_dict)

df1['review_date'] = pd.to_datetime(df1['at'])

df1['title']=None
df1['edited']=None
df1=df1.drop(['userImage','repliedAt','at','appVersion'], axis=1)

rename_column={'reviewId':'id',
               'userName':'username',
               'content':'review',
               'thumbsUpCount':'thumbs_up_count',
               'reviewCreatedVersion':'app_version',
               'replyContent':'reply',
               'appId':'app_name',
               'score':'rating'
              }
df1=df1.rename(columns=rename_column)
df1_final=df1[['id',
              'username',
              'rating',
              'title',
              'review',
              'review_date',
              'app_version',
              'thumbs_up_count',
              'edited',
              'reply',
              'app_name',
              'source']]

df2 = pd.read_csv('/tmp/app_store_reviews.csv')

df2['review_date'] = pd.to_datetime(df2['date'])

df2['reply'] = df2['developerResponse']\
                .apply(lambda x: ast.literal_eval(x) if pd.notnull(x) else None)
df2['reply'] = df2['reply'].apply(lambda x: x['body'] if pd.notnull(x) else None)
df2["reply"] = df2["reply"].str.replace('\n', ' ')
df2["reply"] = df2["reply"].str.replace('\'', '')

df2['id']=None
df2['thumbs_up_count']=None
df2['app_version']=None
df2['source'] = 'appstore'
df2=df2.drop(['date','developerResponse'], axis=1)

rename_dict = {'microsoft-teams':'microsoft teams'}
df2['app_name']=df2['app_name'].replace(rename_dict)

rename_column={'isEdited':'edited',
               'userName':'username'
              }
df2=df2.rename(columns=rename_column)
df2_final=df2[['id',
              'username',
              'rating',
              'title',
              'review',
              'review_date',
              'app_version',
              'thumbs_up_count',
              'edited',
              'reply',
              'app_name',
              'source'
              ]]

df1_final = df1_final.append(df2_final, ignore_index=True)

df1_final["username"] = df1_final["username"].str.replace('\n', ' ')
df1_final["username"] = df1_final["username"].str.replace('\'', '')
df1_final["username"] = df1_final["username"].str.replace(';', ' ')

df1_final["title"] = df1_final["title"].astype(str)
df1_final["title"] = df1_final["title"].apply(lambda x: sub('[^\w\s]', ' ', x))
df1_final["title"] = df1_final["title"].replace(r'\s+', ' ', regex=True)
df1_final["title"] = df1_final["title"].str.strip()
df1_final['title'] = df1_final['title'].str.lower()
df1_final['title'] = df1_final["title"]\
                            .apply(lambda x: ''.join([" " if ord(i) < 32 or ord(i) > 126 else i for i in x]))

df1_final["review"] = df1_final["review"].astype(str)
df1_final["review"] = df1_final["review"].apply(lambda x: sub('[^\w\s]', ' ', x))
df1_final["review"] = df1_final["review"].replace(r'\s+', ' ', regex=True)
df1_final["review"] = df1_final["review"].str.strip()
df1_final['review'] = df1_final['review'].str.lower()
df1_final['review'] = df1_final["review"]\
                            .apply(lambda x: ''.join([" " if ord(i) < 32 or ord(i) > 126 else i for i in x]))

df1_final["reply"] = df1_final["reply"].astype(str)
df1_final["reply"] = df1_final["reply"].apply(lambda x: sub('[^\w\s]', ' ', x))
df1_final["reply"] = df1_final["reply"].replace(r'\s+', ' ', regex=True)
df1_final["reply"] = df1_final["reply"].str.strip()
df1_final['reply'] = df1_final['reply'].str.lower()
df1_final['reply'] = df1_final["reply"]\
                            .apply(lambda x: ''.join([" " if ord(i) < 32 or ord(i) > 126 else i for i in x]))

df1_final.to_csv('all_app_reviews.csv', index=None, header=True)

output_bucket = storage_client.get_bucket(bucket_name)
output_blob = output_bucket.blob(output_file_path)
output_blob.upload_from_filename('/tmp/all_app_reviews.csv')

os.remove('/tmp/relevant_play_store_reviews.csv')
os.remove('/tmp/app_store_reviews.csv')
os.remove('/tmp/all_app_reviews.csv')


import os
from os import path
import pathlib
import shutil
import time

target_folder = "/home/bali/Downloads/"
is_image = ['.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.gif', '.psd', '.webp', '.svg', '.raw', '.arw', '.cr2', '.nrw', '.k25', '.svgz', '.ai', '.eps', '.xcf']
is_video = video_file_extensions = [
    '.264', '.3g2', '.3gp', '.3gp2', '.3gpp', '.3gpp2', '.3mm', '.3p2', '.60d', '.787', '.89', '.aaf', '.aec', '.aep', '.aepx',
    '.aet', '.aetx', '.ajp', '.ale', '.am', '.amc', '.amv', '.amx', '.anim', '.aqt', '.arcut', '.arf', '.asf', '.asx', '.avb',
    '.avc', '.avd', '.avi', '.avp', '.avs', '.avs', '.avv', '.axm', '.bdm', '.bdmv', '.bdt2', '.bdt3', '.bik', '.bin', '.bix',
    '.bmk', '.bnp', '.box', '.bs4', '.bsf', '.bvr', '.byu', '.camproj', '.camrec', '.camv', '.ced', '.cel', '.cine', '.cip',
    '.clpi', '.cmmp', '.cmmtpl', '.cmproj', '.cmrec', '.cpi', '.cst', '.cvc', '.cx3', '.d2v', '.d3v', '.dat', '.dav', '.dce',
    '.dck', '.dcr', '.dcr', '.ddat', '.dif', '.dir', '.divx', '.dlx', '.dmb', '.dmsd', '.dmsd3d', '.dmsm', '.dmsm3d', '.dmss',
    '.dmx', '.dnc', '.dpa', '.dpg', '.dream', '.dsy', '.dv', '.dv-avi', '.dv4', '.dvdmedia', '.dvr', '.dvr-ms', '.dvx', '.dxr',
    '.dzm', '.dzp', '.dzt', '.edl', '.evo', '.eye', '.ezt', '.f4p', '.f4v', '.fbr', '.fbr', '.fbz', '.fcp', '.fcproject',
    '.ffd', '.flc', '.flh', '.fli', '.flv', '.flx', '.gfp', '.gl', '.gom', '.grasp', '.gts', '.gvi', '.gvp', '.h264', '.hdmov',
    '.hkm', '.ifo', '.imovieproj', '.imovieproject', '.ircp', '.irf', '.ism', '.ismc', '.ismv', '.iva', '.ivf', '.ivr', '.ivs',
    '.izz', '.izzy', '.jss', '.jts', '.jtv', '.k3g', '.kmv', '.ktn', '.lrec', '.lsf', '.lsx', '.m15', '.m1pg', '.m1v', '.m21',
    '.m21', '.m2a', '.m2p', '.m2t', '.m2ts', '.m2v', '.m4e', '.m4u', '.m4v', '.m75', '.mani', '.meta', '.mgv', '.mj2', '.mjp',
    '.mjpg', '.mk3d', '.mkv', '.mmv', '.mnv', '.mob', '.mod', '.modd', '.moff', '.moi', '.moov', '.mov', '.movie', '.mp21',
    '.mp21', '.mp2v', '.mp4', '.mp4v', '.mpe', '.mpeg', '.mpeg1', '.mpeg4', '.mpf', '.mpg', '.mpg2', '.mpgindex', '.mpl',
    '.mpl', '.mpls', '.mpsub', '.mpv', '.mpv2', '.mqv', '.msdvd', '.mse', '.msh', '.mswmm', '.mts', '.mtv', '.mvb', '.mvc',
    '.mvd', '.mve', '.mvex', '.mvp', '.mvp', '.mvy', '.mxf', '.mxv', '.mys', '.ncor', '.nsv', '.nut', '.nuv', '.nvc', '.ogm',
    '.ogv', '.ogx', '.osp', '.otrkey', '.pac', '.par', '.pds', '.pgi', '.photoshow', '.piv', '.pjs', '.playlist', '.plproj',
    '.pmf', '.pmv', '.pns', '.ppj', '.prel', '.pro', '.prproj', '.prtl', '.psb', '.psh', '.pssd', '.pva', '.pvr', '.pxv',
    '.qt', '.qtch', '.qtindex', '.qtl', '.qtm', '.qtz', '.r3d', '.rcd', '.rcproject', '.rdb', '.rec', '.rm', '.rmd', '.rmd',
    '.rmp', '.rms', '.rmv', '.rmvb', '.roq', '.rp', '.rsx', '.rts', '.rts', '.rum', '.rv', '.rvid', '.rvl', '.sbk', '.sbt',
    '.scc', '.scm', '.scm', '.scn', '.screenflow', '.sec', '.sedprj', '.seq', '.sfd', '.sfvidcap', '.siv', '.smi', '.smi',
    '.smil', '.smk', '.sml', '.smv', '.spl', '.sqz', '.srt', '.ssf', '.ssm', '.stl', '.str', '.stx', '.svi', '.swf', '.swi',
    '.swt', '.tda3mt', '.tdx', '.thp', '.tivo', '.tix', '.tod', '.tp', '.tp0', '.tpd', '.tpr', '.trp', '.ts', '.tsp', '.ttxt',
    '.tvs', '.usf', '.usm', '.vc1', '.vcpf', '.vcr', '.vcv', '.vdo', '.vdr', '.vdx', '.veg','.vem', '.vep', '.vf', '.vft',
    '.vfw', '.vfz', '.vgz', '.vid', '.video', '.viewlet', '.viv', '.vivo', '.vlab', '.vob', '.vp3', '.vp6', '.vp7', '.vpj',
    '.vro', '.vs4', '.vse', '.vsp', '.w32', '.wcp', '.webm', '.wlmp', '.wm', '.wmd', '.wmmp', '.wmv', '.wmx', '.wot', '.wp3',
    '.wpl', '.wtv', '.wve', '.wvx', '.xej', '.xel', '.xesc', '.xfl', '.xlmv', '.xmv', '.xvid', '.y4m', '.yog', '.yuv', '.zeg',
    '.zm1', '.zm2', '.zm3', '.zmv'
]
is_document = ['.pdf', '.doc', '.docx', '.odt', '.xls', '.xlsx', '.ods', '.ppt', '.pptx', '.txt']
is_program = ['.html', '.htm', '.php', '.py', '.sh', '.sql', '.rpm', '.deb', '.appimage', '.dart', '.css', '.js', '.jsx', '.env', '.json', '.md', '.htaccess', '.log', '.conf', '.xml', '.yml', '.key']
is_compressed = ['.tar', '.gz', '.zip', '.rar', '.xz', '.7zip']
is_font = ['.jfproj', '.ttf', '.pfa', '.woff', '.fnt', '.otf', '.woff2', '.odttf']

def move_file(destination_path, file_name, file_ext, file_name_plain):
    if not path.exists(destination_path):
        os.mkdir(destination_path)
    for files in os.listdir(destination_path):
        file_path = os.path.join(target_folder, files)
        if os.path.exists(destination_path+file_name):
            file_name_new = file_name_plain+"copy("+ str(round(time.time())) +")"+file_ext
    else:
        file_name_new = file_name

    if(os.path.exists(target_folder+file_name)):
        shutil.move(target_folder+file_name, destination_path+file_name_new)

for files in os.listdir(target_folder):
    file_path = os.path.join(target_folder, files)
    if os.path.isfile(file_path):
        file_extension = pathlib.Path(file_path).suffix
        file_name_plain = pathlib.Path(file_path).stem
        if file_extension.lower() in is_image:
            move_file(target_folder + "Images/", files, file_extension, file_name_plain)
        if file_extension.lower() in is_video:
            move_file(target_folder + "Videos/", files, file_extension, file_name_plain)
        if file_extension.lower() in is_document:
            move_file(target_folder + "Documents/", files, file_extension, file_name_plain)
        if file_extension.lower() in is_program:
            move_file(target_folder + "Programs/", files, file_extension, file_name_plain)
        if file_extension.lower() in is_compressed:
            move_file(target_folder + "Compressed/", files, file_extension, file_name_plain)
        if file_extension.lower() in is_font:
            move_file(target_folder + "Fonts/", files, file_extension, file_name_plain)
        else :
            move_file(target_folder + "Miscs/", files, file_extension, file_name_plain)


from customer import Customer
from server import Server

class System:
  time = 0 # This variable keeps track of the time
  lm = 0 # This variable serves as lambda, the mean arrival rate
  servers = []
  queue = [] # This list contains all customers awaiting service
  fel = [] # This list keeps track of future events (arrivals and departures)
  verbose = False
  numInQueue = 0
  numInService = 0
  numInSystem = 0
  custRepo = [] # This list is a repository of all customers over time
  numArrivals = 0
  servCompletns = 0

  def __init__(self, servers, lm, verbose=False):
    self.lm = lm
    self.servers = servers
    self.queue = []
    self.fel = []
    self.verbose = verbose
    self.custRepo = []
    self.numInQueue = 0
    self.numInService = 0
    self.numInSystem = 0
    self.numArrivals = 0
    self.servCompletns = 0

  def get_num_in_queue(self):
    # This method returns the number of customers curently awaiting service
    return len(self.queue)

  def get_num_in_service(self):
    # This method returns the number of customers currently in service
    res = 0
    for server in self.servers:
      if server.is_busy: res += 1
    return res

  def get_num_in_system(self):
    # This method returns the number of customers currently in the system
    return self.get_num_in_queue() + self.get_num_in_service()

  def updateStats(self, eventTime):
    # This method updates three statistics over time:
    #   total queue length
    #   total number of customers in service
    #   total number of customers in the system
    dt = eventTime - self.time
    self.numInQueue += self.get_num_in_queue() * dt
    self.numInService += self.get_num_in_service() * dt
    self.numInSystem += self.get_num_in_system() * dt

  def find_free_server(self):
    # This method returns any free server, or None if all servers are busy
    for server in self.servers:
      if server.is_busy == False:
        return server
    return None

  def generateInterarrival(self):
    # This method returns an inter-arrival time:
    #   Currently, an expolnential interarrival time is being used
    #   This can be modified to utilize any other distribution
    return random.expovariate( 1.0 / self.lm )

  def addEvent(self, eventType, eventTime):
    # This method adds an event to the future event list
    self.fel.append((eventType, eventTime))

  def deleteEvent(self, index):
    # This method removes an event from the future event list
    self.fel.pop(index)

  def findNextEvent(self):
    # This method find the next event from the future event list
    earliestTime = 1e30
    earliestIndex = -1
    for i in range( len( self.fel ) ):
      event = self.fel[ i ]
      eventTime = event[ 1 ]
      if ( eventTime < earliestTime ):
        earliestTime = eventTime
        earliestIndex = i
    return earliestIndex

  def handleArrival(self, customer, eventTime):
    # When an arrival occurs, this method routes the customer accordingly
    self.updateStats(eventTime)
    self.numArrivals += 1
    if self.verbose:
      print()
      print("customer ", customer.ID, " arrives at time ", eventTime)
    self.custRepo.append(customer)
    server = self.find_free_server()
    if server == None: # If no server is free
      self.queue.append(customer) # The customer is sent to the back of the queue
      if self.verbose:print("no servers available, queue length is ", len(self.queue))
    else: # If a free server exists
      if self.verbose:print("server ", server.ID, " is free")
      st = server.generateService() # The next customer's service time is generated
      self.addEvent("d"+str(server.ID), st + eventTime) # Service completion event is scheduled
      self.serviceStart(server, customer, eventTime)
      if self.verbose:print("service completion scheduled for ", st+eventTime)
    next_arrival = eventTime + self.generateInterarrival()
    self.addEvent("a", next_arrival) # The following arrival is scheduled
    self.time = eventTime
    if self.verbose:print("next arrival at time ", next_arrival)

  def handleServiceComp(self, server, eventTime):
    # When a service completion occurs, this method routes awaiting customers accordingly
    self.updateStats(eventTime)
    self.servCompletns += 1
    if self.verbose:
      print()
      print("server ", server.ID, "is finished with customer ", server.customer.ID, "at time ", eventTime)
    server.is_busy = False
    server.customer.t_dep = eventTime
    server.customer = None
    if len(self.queue) > 0: # If there are customers waiting in the queue
      if self.verbose:print("queue is ", len(self.queue), "customers long")
      st = server.generateService() # The next customer's service time is generated
      self.addEvent("d"+str(server.ID), st + eventTime) # Service completion event is scheduled

      self.serviceStart(server, self.queue.pop(0), eventTime) # An awaiting customer begins service,
      #    currently the first customer in line is chosen,
      #    but, this can be changed to take a customer from anywhere in the queue

      if self.verbose:print("service completion scheduled for ", st+eventTime)
    self.time = eventTime

  def serviceStart(self, server, customer, t_serv):
    # This method assigns `customer` to `server` for service beginning at time `t_serv`
    if self.verbose:
      print()
      print("server ", server.ID, "takes into service customer ", customer.ID, " at time ", t_serv)
    server.is_busy = True
    server.customer = customer
    customer.t_serv = t_serv # Update the customers time of beginning service

  def getServer(self, ID):
    # Given an ID, this method returns the respective server
    for server in self.servers:
      if server.ID == ID:
        return server
    return None


from dataclasses import dataclass, field
from typing import List, Optional
from ojp.natural_language_string_structure import NaturalLanguageStringStructure

__NAMESPACE__ = "http://www.siri.org.uk/siri"

@dataclass
class StopAssignmentStructure:
    """
    Type for assignment of a SCHEDULED STOP POINT to a specific QUAY or platform
    +SIRI v2.0.

    :ivar aimed_quay_ref: Physical QUAY to use according to the planned
        timetable. +SIRI v2.0
    :ivar aimed_quay_name: Scheduled Platform name. Can be used to
        indicate platfrom change. +SIRI v2.0
    :ivar expected_quay_ref: Physical QUAY to use accoring to the real-
        time prediction. +SIRI v2.0
    :ivar actual_quay_ref: Physical QUAY actually used. +SIRI v2.0
    """
    aimed_quay_ref: Optional[str] = field(
        default=None,
        metadata={
            "name": "AimedQuayRef",
            "type": "Element",
            "namespace": "http://www.siri.org.uk/siri",
        }
    )
    aimed_quay_name: List[NaturalLanguageStringStructure] = field(
        default_factory=list,
        metadata={
            "name": "AimedQuayName",
            "type": "Element",
            "namespace": "http://www.siri.org.uk/siri",
        }
    )
    expected_quay_ref: Optional[str] = field(
        default=None,
        metadata={
            "name": "ExpectedQuayRef",
            "type": "Element",
            "namespace": "http://www.siri.org.uk/siri",
        }
    )
    actual_quay_ref: Optional[str] = field(
        default=None,
        metadata={
            "name": "ActualQuayRef",
            "type": "Element",
            "namespace": "http://www.siri.org.uk/siri",
        }
    )


import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
#https://stackoverflow.com/questions/61867945/python-import-error-cannot-import-name-six-from-sklearn-externals
#Fixed six import issue using stackoverflow from above
import six
import sys
sys.modules['sklearn.externals.six'] = six
import mlrose
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
import time

data = pd.read_csv("file")
X = data.iloc[:,2:-1]
Y = data.iloc[:,-1:]
Xtrain, Xtest, ytrain, ytest = train_test_split(X,Y,test_size=.2, random_state=0)
scaler = MinMaxScaler()
print()
Xtrain = scaler.fit_transform(Xtrain)
Xtest = scaler.transform(Xtest)
randhillacc_table = []
simacc_table = []
genacc_table = []

randhillacc_test = []
simacc_test = []
genacc_test = []

#Placing in loop allows for a accurate plot graph
for i in range(1,1000,200):

    model = mlrose.NeuralNetwork(hidden_nodes = [2], activation = 'relu', \
                                     algorithm = 'random_hill_climb', max_iters = i, \
                                     bias = True, is_classifier = True, learning_rate = 0.1, \
                                     early_stopping = True, clip_max = 2, max_attempts = 100, \
                                     random_state = 3)

    model.fit(Xtrain, ytrain)
    pred = model.predict(Xtrain)
    trainval_x = accuracy_score(ytrain, pred)
    randhillacc_table.append(trainval_x)

    testpred = model.predict(Xtest)
    testval_x = accuracy_score(ytest, testpred)
    randhillacc_test.append(testval_x)

    modely = mlrose.NeuralNetwork(hidden_nodes = [2], activation = 'relu', \
                                     algorithm = 'simulated_annealing', max_iters = i, \
                                     bias = True, is_classifier = True, learning_rate = 0.1, \
                                     early_stopping = True, clip_max = 2, max_attempts = 100, \
                                     random_state = 3)

    modely.fit(Xtrain, ytrain)
    pred = modely.predict(Xtrain)
    trainval_y = accuracy_score(ytrain, pred)
    simacc_table.append(trainval_y)

    testpred = modely.predict(Xtest)
    testval_y = accuracy_score(ytest, testpred)
    simacc_test.append(testval_y)

    modelz = mlrose.NeuralNetwork(hidden_nodes = [2], activation = 'relu', \
                                     algorithm = 'genetic_alg', max_iters = i, \
                                     bias = True, is_classifier = True, learning_rate = 0.1, \
                                     early_stopping = True, clip_max = 2, max_attempts = 100, \
                                     random_state = 3)

    modelz.fit(Xtrain, ytrain)
    pred = modelz.predict(Xtrain)
    trainval_z = accuracy_score(ytrain, pred)
    genacc_table.append(trainval_z)

    testpred = modelz.predict(Xtest)
    testval_z = accuracy_score(ytest, testpred)
    genacc_test.append(testval_z)

plt.plot(np.arange(1, 1000,200), np.array(randhillacc_table), label='Random Hill Climb')
plt.plot(np.arange(1, 1000,200), np.array(simacc_table), label='Simulated Annealing')
plt.plot(np.arange(1, 1000,200), np.array(genacc_table), label='Genetic Algorithm')
plt.xlabel('Iterations')
plt.ylabel('Training Acccuracy')
plt.title('Training Rates')
plt.legend()
plt.show()
print(np.array(model))
print(accuracy_score(ytrain, pred))

print("RHC {}, SIM {}, GEN {}.".format(trainval_x, trainval_y, trainval_z))

plt.figure()
plt.plot(np.arange(1, 1000,200), np.array(randhillacc_test), label='Random Hill Climb')
plt.plot(np.arange(1, 1000,200), np.array(simacc_test), label='Simulated Annealing')
plt.plot(np.arange(1, 1000,200), np.array(genacc_test), label='Genetic Algorithm')
plt.xlabel('Iterations')
plt.ylabel('Test Accuracy')
plt.title('Testing Rates')
plt.legend()
plt.show()

#From mlrose
def random_hill_climb(problem, max_attempts=10, max_iters=np.inf, restarts=0,
                      init_state=None, curve=False, random_state=None):

    if (not isinstance(max_attempts, int) and not max_attempts.is_integer()) \
       or (max_attempts < 0):
        raise Exception("""max_attempts must be a positive integer.""")

    if (not isinstance(max_iters, int) and max_iters != np.inf
            and not max_iters.is_integer()) or (max_iters < 0):
        raise Exception("""max_iters must be a positive integer.""")

    if (not isinstance(restarts, int) and not restarts.is_integer()) \
       or (restarts < 0):
        raise Exception("""restarts must be a positive integer.""")

    if init_state is not None and len(init_state) != problem.get_length():
        raise Exception("""init_state must have same length as problem.""")

    # Set random seed
    if isinstance(random_state, int) and random_state > 0:
        np.random.seed(random_state)

    best_fitness = -1*np.inf
    best_state = None

    if curve:
        fitness_curve = []

    for _ in range(restarts + 1):
        if init_state is None:
            problem.reset()
        else:
            problem.set_state(init_state)

        attempts = 0
        iters = 0

        while (attempts < max_attempts) and (iters < max_iters):
            iters += 1

            next_state = problem.random_neighbor()
            next_fitness = problem.eval_fitness(next_state)

            if next_fitness > problem.get_fitness():
                problem.set_state(next_state)
                attempts = 0

            else:
                attempts += 1

            if curve:
                fitness_curve.append(problem.get_fitness())

        # Update best state and best fitness
        if problem.get_fitness() > best_fitness:
            best_fitness = problem.get_fitness()
            best_state = problem.get_state()

    best_fitness = problem.get_maximize()*best_fitness

    if curve:
        return best_state, best_fitness, np.asarray(fitness_curve)

    return best_state, best_fitness
#From mlrose
def simulated_annealing(problem, schedule=mlrose.GeomDecay(), max_attempts=10,
                        max_iters=np.inf, init_state=None, curve=False,
                        random_state=None):

    if (not isinstance(max_attempts, int) and not max_attempts.is_integer()) \
       or (max_attempts < 0):
        raise Exception("""max_attempts must be a positive integer.""")

    if (not isinstance(max_iters, int) and max_iters != np.inf
            and not max_iters.is_integer()) or (max_iters < 0):
        raise Exception("""max_iters must be a positive integer.""")

    if init_state is not None and len(init_state) != problem.get_length():
        raise Exception("""init_state must have same length as problem.""")

    # Set random seed
    if isinstance(random_state, int) and random_state > 0:
        np.random.seed(random_state)

    # Initialize problem, time and attempts counter
    if init_state is None:
        problem.reset()
    else:
        problem.set_state(init_state)

    if curve:
        fitness_curve = []

    attempts = 0
    iters = 0

    while (attempts < max_attempts) and (iters < max_iters):
        temp = schedule.evaluate(iters)
        iters += 1

        if temp == 0:
            break

        else:
            # Find random neighbor and evaluate fitness
            next_state = problem.random_neighbor()
            next_fitness = problem.eval_fitness(next_state)

            # Calculate delta E and change prob
            delta_e = next_fitness - problem.get_fitness()
            prob = np.exp(delta_e/temp)

            # If best neighbor is an improvement or random value is less
            # than prob, move to that state and reset attempts counter
            if (delta_e > 0) or (np.random.uniform() < prob):
                problem.set_state(next_state)
                attempts = 0

            else:
                attempts += 1

        if curve:
            fitness_curve.append(problem.get_fitness())

    best_fitness = problem.get_maximize()*problem.get_fitness()
    best_state = problem.get_state()

    if curve:
        return best_state, best_fitness, np.asarray(fitness_curve)

    return best_state, best_fitness
#From mlrose
def genetic_alg(problem, pop_size=200, mutation_prob=0.1, max_attempts=10,
                max_iters=np.inf, curve=False, random_state=None):

    if pop_size < 0:
        raise Exception("""pop_size must be a positive integer.""")
    elif not isinstance(pop_size, int):
        if pop_size.is_integer():
            pop_size = int(pop_size)
        else:
            raise Exception("""pop_size must be a positive integer.""")

    if (mutation_prob < 0) or (mutation_prob > 1):
        raise Exception("""mutation_prob must be between 0 and 1.""")

    if (not isinstance(max_attempts, int) and not max_attempts.is_integer()) \
       or (max_attempts < 0):
        raise Exception("""max_attempts must be a positive integer.""")

    if (not isinstance(max_iters, int) and max_iters != np.inf
            and not max_iters.is_integer()) or (max_iters < 0):
        raise Exception("""max_iters must be a positive integer.""")

    # Set random seed
    if isinstance(random_state, int) and random_state > 0:
        np.random.seed(random_state)

    if curve:
        fitness_curve = []

    # Initialize problem, population and attempts counter
    problem.reset()
    problem.random_pop(pop_size)
    attempts = 0
    iters = 0

    while (attempts < max_attempts) and (iters < max_iters):
        iters += 1

        # Calculate breeding probabilities
        problem.eval_mate_probs()

        # Create next generation of population
        next_gen = []

        for _ in range(pop_size):
            # Select parents
            selected = np.random.choice(pop_size, size=2,
                                        p=problem.get_mate_probs())
            parent_1 = problem.get_population()[selected[0]]
            parent_2 = problem.get_population()[selected[1]]

            # Create offspring
            child = problem.reproduce(parent_1, parent_2, mutation_prob)
            next_gen.append(child)

        next_gen = np.array(next_gen)
        problem.set_population(next_gen)

        next_state = problem.best_child()
        next_fitness = problem.eval_fitness(next_state)

        # If best child is an improvement,
        # move to that state and reset attempts counter
        if next_fitness > problem.get_fitness():
            problem.set_state(next_state)
            attempts = 0

        else:
            attempts += 1

        if curve:
            fitness_curve.append(problem.get_fitness())

    best_fitness = problem.get_maximize()*problem.get_fitness()
    best_state = problem.get_state()

    if curve:
        return best_state, best_fitness, np.asarray(fitness_curve)

    return best_state, best_fitness


import pandas as pd
import chart_studio.plotly as py
from plotly.offline import init_notebook_mode,plot,download_plotlyjs
import plotly.graph_objects as go

import os

def excercise1():
    init_notebook_mode(connected=True)

    df = pd.read_csv(os.getcwd() + '/' + '2014_World_Power_Consumption' )

    print(df.head())

    data = dict( type='choropleth',
                locations=df['Country'],
                locationmode='country names',
                text=df['Text'],
                z=df['Power Consumption KWH'],
                colorbar= {'title' : '2014 World Power Consumption Data'})

    layout = dict(title= '2014 World Power Consumption Data',
                  geo= dict(showframe=False, projection= {'type' : 'robinson'}))

    choromap1 =go.Figure(data=[data], layout=layout)

    plot(choromap1)

def excercise2():
    df = pd.read_csv(os.getcwd() + '/' + '2012_Election_Data')

    print(df.columns)
    print(df.head())

    data=dict(type='choropleth',
              locations=df['State Abv'],
              locationmode='USA-states',
              z=df['Voting-Age Population (VAP)'],
              text=df['State'],
              colorbar={'title' : '2012 Election Data'})

    layout=dict(title='2012 Election Data',
                geo=dict(scope='usa', showlakes=True, lakecolor='rgb(85, 173, 240)'))

    choromap1 = go.Figure(data=[data], layout=layout)

    plot(choromap1)

if __name__ == "__main__":
    #excercise1()
    excercise2()


import attr
from attr.validators import instance_of
from pathlib import Path
from typing import Union

@attr.s(frozen=True)
class BatFile:
    """File object path attribute and several metadata attributes.
    Instantiated by the ProcessFilelist class, passed to the ProcessData class
    Attributes: path, fname, experiment."""
    path = attr.ib(validator=instance_of(Path))
    fname = attr.ib(validator=instance_of(str))
    date = attr.ib(validator=instance_of(str))
    tent = attr.ib(validator=instance_of(str))
    # maybe add user input...
    env = attr.ib(validator=instance_of(str))
    # bat_name = attr.ib(validator=instance_of(str))
    # tag = attr.ib(validator=instance_of(str))
    # cond (right or left)

# @attr.s
class ProcessFile:
    """Pipeline to process a list of files.
    Reads attributes from filename and creates a list of EyeFile objects to pass.
    Attributes: filelist, invalid_files, eyedict.
    Methods: instantiate_eye_file, assert_csv, extract_file_attrs.
    """
    # filelist = attr.ib(validator=instance_of(list))
    # batitem = attr.ib() #  BatFile instances to pass forward
    # invalid_files = attr.ib(default=attr.Factory(list)) ### should add invalid files output ###
    def __init__(self, filelist):
        self.filelist = filelist
        self.invalid_files = []

    def get_file_attrs(self) -> None:
        """Analizes file attributes and instantiate BatFile objects"""
        for batfile in self.filelist:
            path = Path(batfile)
            fname = path.name
            if not self.assert_csv(path): # accepts only .csv files
                self.invalid_files.append(fname)
                continue

            fattrs = self.extract_file_attrs(fname)
            if not fattrs: # accepts files only if named in the appropriate pattern
                self.invalid_files.append(fname)
                continue
            date, tent = fattrs[0], fattrs[1]

            if 'slow' in fname:
                env = 'slow'
            elif 'fast' in fname:
                env = 'fast'
            elif 'test' in fname:
                env = 'test'
            else: # accepts only slow, fast or test files
                self.invalid_files.append(fname)
                continue
            self.instantiate_bat_file(path, fname, date, tent, env)

    def assert_csv(self, path: Path) -> bool:
        """Asserts that a file is a csv file"""
        return str.lower(path.suffix) == '.csv'

    def extract_file_attrs(self, fname: str) -> Union[list, bool]:
        """If the file named appropriately, extracts its attributes from filename"""
        fattrs = fname.split('_')
        # return fattrs if len(fattrs) == 10 else False
        return fattrs

    def instantiate_bat_file(self, path: Path, fname: str, date: str, tent: str, env: str) -> BatFile:
        """Instantiates BatFile objects"""
        self.batitem = BatFile(path=path, fname=fname, date=date, tent=tent, env=env) #to add user input too

if __name__ == "__main__":
    # filelist =    ['/Users/gonina/Dropbox/classes/machine_learning/project/1_clio/After feeding/food/Yovel_20190513_3_neg.txt','/Users/gonina/Dropbox/classes/machine_learning/project/1_clio/After feeding/food/Yovel_20190513_3_pos.txt']
    filelist =    ['/Users/gonina/Library/Mobile Documents/com~apple~CloudDocs/lab/python_codes/feeders/feeders analysis/2020-03-20-07_B_Shin_slow.csv']
    files = ProcessFile(filelist)
    files.get_file_attrs()

    print(files.batitem)


from django.contrib.auth import login
from django.shortcuts import render, redirect
from .forms import RegisterForm
from django.contrib.auth.models import Group
# Create your views here.

def register(response):
    if response.method == "POST":
        form = RegisterForm(response.POST)
        if form.is_valid():
            user = form.save()
            group = Group.objects.get(name="Solicitante")
            user.groups.add(group)
            return redirect("/login")
        else:
            return render(response, "register/register.html", {"form": form})
    else:
        form = RegisterForm()
    return render(response, "register/register.html", {"form": form})


from django.db import models

class Profile(models.Model):
    FIRSTNAME_MAX_LENGTH = 20
    LASTNAME_MAX_LENGTH = 20

    first_name = models.CharField(
        max_length=FIRSTNAME_MAX_LENGTH,
        verbose_name='First Name',
    )

    last_name = models.CharField(
        max_length=LASTNAME_MAX_LENGTH,
        verbose_name='Last Name',
    )

    age = models.IntegerField(
        verbose_name='Age',
    )

    image = models.URLField(
        verbose_name='Link to Profile Image',
    )

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

class Note(models.Model):
    TITLE_MAX_LENGTH = 30

    title = models.CharField(
        max_length=TITLE_MAX_LENGTH,
        verbose_name="Title",
    )

    image = models.URLField(
        verbose_name="Link To Image",
    )

    content = models.TextField(
        verbose_name="Content",
    )

    def __str__(self):
        return self.title


from django import forms
from .models import Schoolrool,Familymemberone,Familymembertwo

class Schoolroolform(forms.ModelForm):
    class Meta:
        model = Schoolrool
        fields = '__all__'
        exclude = ['province_ID','country_ID']
        labels = {
        'name':'姓名',
        'alread_name':'曾用名',
        'sex':'性别',
        'IDcard':'身份证号',
        'nation':'民族',
        'school':'学校',
        'grade':'年级',
        'class_bj':'班级',
        'by_type':'户口性质',
        'address':'现住地址',
        'is_child':'是否是独生子女',
        'is_leftover_child':'是否留守儿童',
        'is_healdy':'健康状况',
        'entrance_date':'入学年月',
        'entrance_go':'入学方式',
        'how_go_school':'就读方式',
        'is_disable':'是否残疾人',
        'country_ID':'国网学籍号',
        'province_ID':'省网学籍号',
        }
    def clean(self):
        name = self.cleaned_data['name']
        print(1111)
        return self.cleaned_data
#['alread_name','name','sex','IDcard','nation','school','grade','class_bj','by_type','address','is_child','is_leftover_child','is_healdy','entrance_date','entrance_go','how_go_school','is_disable','country_ID','province_ID']
#['member_name_one','member_ralation_one','member_address_one','member_phone_one','is_guardian_one','member_idcard_one','member_nation_one','member_job_one','member_duty_one']
#['member_name_two','member_nation_two','member_idcard_two','member_ralation_two','member_address_two','member_phone_two','is_guardian_two','member_job_two','member_duty_two']

class Familymemberoneform(forms.ModelForm):
    class Meta:
        model = Familymemberone
        fields = ['member_name_one','member_nation_one','member_idcard_one','member_ralation_one','member_address_one','member_phone_one','is_guardian_one','member_job_one','member_duty_one']
        labels ={
            'name':'姓名',
            'member_name_one':'成员1姓名',
            'member_ralation_one':'成员1关系',
            'member_address_one':'成员1地址',
            'member_phone_one':'成员1电话',
            'is_guardian_one':'成员1是否监护人',
            'member_idcard_one':'成员1身份证号',
            'member_nation_one':'成员1民族',
            'member_job_one':'成员1工作单位',
            'member_duty_one':'成员1职务',
        }

class Familymembertwoform(forms.ModelForm):
    class Meta:
        model = Familymembertwo
        fields = ['member_name_two','member_nation_two','member_idcard_two','member_ralation_two','member_address_two','member_phone_two','is_guardian_two','member_job_two','member_duty_two']
        labels ={
            'name':'姓名',
            'member_name_two':'成员2姓名',
            'member_ralation_two':'成员2关系',
            'member_address_two':'成员2地址',
            'member_phone_two':'成员2电话',
            'is_guardian_two':'成员2是否监护人',
            'member_idcard_two':'成员2身份证号',
            'member_nation_two':'成员2民族',
            'member_job_two':'成员2工作单位',
            'member_duty_two':'成员2职务',
        }

class Alterstudentinfo(forms.Form):
    IDcard = forms.CharField(label='身份证号',max_length=18)
'''
    def clean(self):
        IDcard = self.cleaned_data['IDcard']
        if Schoolrool.objects.filter(IDcard=IDcard).exists():
        else:
            raise forms.ValidationError("你查询的学生不存在，请先注册！")
        return IDcard

'''


'''from functools import reduce
a=[1,2,3,4,5,6,7,8]
b=list(map(lambda x:x>3,a))
print(b)
c=list(filter(lambda x:x>3,a))
print(c)
d=reduce(lambda x,y:x+y,a)
print(d)
e=reduce(lambda x,y:x+y,map(lambda x:x+3,filter(lambda x:x>3,a)))
print(e)

quadratic_equation=lambda x,y:(x**2)+(y**2)
print(quadratic_equation(3,4))

def linear_equation(o,p):
    print(lambda o,p:(3*o)+(4*p))
linear_equation(2,2)

l=[5,6,4,3,7,8,1,9,12,43,21]
print(l.sort())'''
from functools import reduce
restart=('Y')
while restart not in ('n','N','no','NO'):
    print('1.Detect if the given number is octal number')
    print('2.pass and sum the list to the method and return value')
    print('3.check the number is less than 10')
    print('4.exit the menu')
    menu=int(input('enter your choice:'))
    if menu==1:
        try:
            num=int(input("enter octal number:"),8)
            print("num(decimal format):",num)
            print("num(octal format):",oct(num))
        except ValueError:
            print("Plese enter only Octal Value")
        restart='Y'
    elif menu==2:
        def my_function(numbers):
            for x in numbers:
                print(x)

        inputs=list(input('enter sequence of numbers').split())
        my_function(inputs)
        print('sum of numbers:',reduce(lambda x,y:x+y,inputs))
        restart = 'Y'
    elif menu==3:
        input=list(input('enter sequence of numbers').split())
        print(input)
        restart = 'Y'
    elif menu==4:
        print('Thank You')
        break


"""
- This sheet will process and clean data in DataFrame follow standard
- After that, return df_clean

"""
from Extract_To_DataFrame import *
from pyspark.sql import SparkSession
from pyspark.sql.functions import split, col, lit
from queries_db import *
from Parameter import *
from datetime import date
from pyspark.sql.functions import udf
import datetime as dt

def Process_Mapping_Dim(df_port,df_state, df_mode, df_visa, df_country, Dim):
    """
    - process mapping dim
    - input dim data frame from extract module
    - output: clean dim data Frame after process
    """
    Dimmesion = Dim
    spark = create_sparksession()

    if Dimmesion == 'port_dim':
        # read dimmension df:

        # clean df_port: split port_cd -->  update port_cd and add new column name "sta_cd"
        split_value = df_port['port_nm'].str.split(", ", n = 1, expand = True)
        df_port['port_nm'] = split_value[0]
        df_port['sta_cd']  = split_value[1]

        # clean record have value not in US or not defined: join with df_state
        df_state_join = df_state['sta_cd'].str.replace("\t", "")
        df_port_clean = pd.merge(df_port, df_state_join, left_on= 'sta_cd', right_on='sta_cd', how='inner')

        # final --> select cloumn: 'port_cd', 'port_nm','sta_cd', 'lst_mdf_data_x'
        df_port_clean = df_port_clean[['port_cd', 'port_nm','sta_cd', 'lst_mdf_data']]
        df_port_clean = spark.createDataFrame(df_port_clean)

        return df_port_clean

    elif Dimmesion == 'state_dim':
        df_state['sta_cd'] = df_state['sta_cd'].str.replace("\t", "")
        df_state_clean = spark.createDataFrame(df_state)
        return df_state_clean

    elif Dimmesion == 'mode_dim':
        df_mode_clean = spark.createDataFrame(df_mode)
        return df_mode_clean
    # clean visa dim:
    elif Dimmesion == 'visa_dim':
        df_visa_clean = spark.createDataFrame(df_visa)
        return df_visa_clean

    # clean country: có nhiều mã quốc gia không hợp lệ, không tồn tại ==> chuyển về 'OTHER'
    elif Dimmesion == 'country_dim':
        df_country.loc[df_country['cntr_nm'].str.contains('No Country'), 'cntr_nm'] = 'OTHER'
        df_country.loc[df_country['cntr_nm'].str.contains('INVALID'), 'cntr_nm'] = 'OTHER'
        df_cntr_clean = spark.createDataFrame(df_country)

        return df_cntr_clean

def Process_Temp(df_temp):
    """
    - xử lý và làm sạch dữ liệu Temp theo phương án làm sạch đã đưa ra
    - sau đó, trả về df_temp_clean

    """
    # time in 2016:
    # only US:
    df_temp_clean = df_temp.filter(df_temp.Country =='US')\
                           .filter(df_temp.Year == '2016')\
                           .withColumn("lst_mdf_data", lit(date.today().strftime("%Y%m%d")))\
                           .withColumnRenamed("State", "sta_nm")\
                           .withColumnRenamed("City", "cit")\
                           .withColumnRenamed("Month", "mon")\
                           .withColumnRenamed("Year", "yr")\
                           .withColumnRenamed("AvgTemperature", "avg_temp")\
                           .drop("Region")\
                           .drop("Country")
    print("already cleaned temp data")
    return df_temp_clean

def Process_Airport(df_airport):
    """
    process airport data
    """
    # clean data:
    df_airport_clean = df_airport.filter(df_airport.iso_country == 'US')\
                             .withColumn("sta_cd", split(col("iso_region"), "-")[1])\
                             .withColumn("lst_mdf_data", lit(date.today().strftime("%Y%m%d")))\
                             .withColumnRenamed("ident", "arpt_cd")\
                             .withColumnRenamed("elevation_ft", "ele_ft")\
                             .withColumnRenamed("iso_country", "cntr")\
                             .withColumnRenamed("name", "arpt_nm")\
                             .withColumnRenamed("municipality", "mun")\
                             .withColumnRenamed("type", "arpt_tp")\
                             .withColumnRenamed("gps_code", "gps_cd")\
                             .withColumnRenamed("local_code", "local_cd")\
                             .drop("iso_region")\
                             .drop("coordinates")\
                             .drop("continent")\
                             .drop("iata_code")
    print("already cleaned airport data")
    return df_airport_clean

def Process_city_demo(df_city_demo):

    # process:delelte record has state field null. After that clean duplicate record at 3 field: state, city, race:
    df_city_demo_clean = df_city_demo.filter(df_city_demo.State.isNotNull())\
                                     .withColumn("LST_MDF_DATA", lit(date.today().strftime("%Y%m%d")))\
                                     .dropDuplicates(subset = ['State', 'City', 'Race'])\
                                     .withColumnRenamed("City", "CIT")\
                                     .withColumnRenamed("Median Age", "MD_AG")\
                                     .withColumnRenamed("Male Population", "M_PPLT")\
                                     .withColumnRenamed("Female Population", "FM_PPLT")\
                                     .withColumnRenamed("Total Population", "TT_PPLT")\
                                     .withColumnRenamed("Number of Veterans", "NUM_VTR")\
                                     .withColumnRenamed("Foreign-born", "FRN_BR")\
                                     .withColumnRenamed("Average Household Size", "AVR_HOSE_SZ")\
                                     .withColumnRenamed("State Code", "STA_CD")\
                                     .withColumnRenamed("Race", "RAC")\
                                     .withColumnRenamed("Count", "CNT")\
                                     .drop("State")
    print("already cleaned city_demo data")
    return df_city_demo_clean

def Process_i94_immigration(df_i94,df_state_clean, df_visa_clean, df_mode_clean):
    """
    - INPUT: dataframe df_94, df_state, df_visa, df_mode
    - OUTPUT: df_i94_clean

    """
    # call datafram extract
    spark = create_sparksession()
    # make temp table
    df_state_clean.createOrReplaceTempView("df_state_clean")
    df_visa_clean.createOrReplaceTempView("df_visa_clean")
    df_mode_clean.createOrReplaceTempView("df_mode_clean")
    df_i94.createOrReplaceTempView("df_i94")

    # clean data:
    df_i94_clean = spark.sql("""
                            select
                                   i.cicid as id
                                  ,i.i94yr as yr
                                  ,i.i94mon as mon
                                  ,i.i94cit as cit
                                  ,i.i94res as res
                                  ,i.i94port as port
                                  ,i.arrdate as arrdt
                                  ,coalesce(m.mode_cd, 'other') as mode
                                  ,coalesce(s.sta_cd, '99') as state
                                  ,i.depdate as depdt
                                  ,i.i94bir as bir
                                  ,coalesce(v.visa_cd, 'other') as visa_cd
                                  ,i.dtadfile as dtadfile
                                  ,i.occup as occup
                                  ,i.gender as gender
                                  ,i.airline as airline
                                  ,i.fltno as fltno
                                  ,i.visatype as visa_tp
                                  ,i.lst_mdf_data as lst_mdf_data

                            from df_i94 i left join df_mode_clean m on i.i94mode = m.mode_cd
                                      left join df_visa_clean v on i.i94visa = v.visa_cd
                                      left join df_state_clean s on i.i94addr = s.sta_cd

                            """)
    get_date = udf(lambda x: (dt.datetime(1960, 1, 1).date() + dt.timedelta(x)).isoformat() if x else None)
    # clean data: only date add data in file > 20160101 and drop duplicate value of some field
    df_i94_clean = df_i94_clean.filter(df_i94_clean.dtadfile > '20160101')\
                            .dropDuplicates(subset = ['id','yr', 'mon', 'cit', 'port', 'arrdt'])\
                            .withColumnRenamed("id", "i94_id")\
                            .withColumnRenamed("port", "port_cd")\
                            .withColumnRenamed("state", "sta_cd")\
                            .withColumnRenamed("mode", "mode_cd")\
                            .withColumn("arrdt", get_date(df_i94_clean.arrdt))
    print("already processed i94 data")

    return df_i94_clean


import numpy as np
import networkx as nx
import random
import argparse
import math
import multiprocessing as mp
import more_itertools as mit
from functools import partial
import gc

def parse_args():
	parser = argparse.ArgumentParser(description="Run random walks.")

	parser.add_argument('--input', nargs='?', default='shufData/digg_truncate.txt',
	                    help='Input graph path')

	parser.add_argument('--output', nargs='?', default='graphwalk/digg_timewalk.txt',
	                    help='output graph path')

	parser.add_argument('--walk-length', type=int, default=5,
	                    help='Length of walk per source.')

	parser.add_argument('--batch_num', type=int, default=20,
	                    help='The number of batches for loading the input graph. Please set it as a big value such as 20 to improve efficiency and avoid memory overflow.')

	parser.add_argument('--cpu', type=int, default=50,
	                    help='The number of cpus for parallel processing.')

	parser.add_argument('--num-walks', type=int, default=10,
	                    help='Number of walks per source.')

	parser.add_argument('--p', type=float, default=0.5,
	                    help='Return hyperparameter.')

	parser.add_argument('--q', type=float, default=1.0,
	                    help='Inout hyperparameter.')

	parser.add_argument('--decay', type=float, default=1.5,
	                    help='weight decay constant.')

	parser.add_argument('--portion', type=float, default=0.7,
	                    help='portion of first/second layer samples for hungry nodes which do not have neighbors based on the time constraint.')

	return parser.parse_args()

class Walker:
	def __init__(self,num_walks,walk_length,decay,q,p,batch_num):
		'''
		Reads the input network in networkx.
		'''
		self.G = None
		self.batch_num=batch_num
		self.size= 0
		self.walks=args.num_walks
		self.walk_length=args.walk_length
		self.decay = args.decay
		self.contextsize=self.walks*self.walk_length
		self.visnode=np.zeros((self.size,),dtype=np.bool)
		self.visprob=[[] for i in range(self.size)]
		self.visneigh=[[] for i in range(self.size)]
		self.visweight=[[] for i in range(self.size)]
		self.lay2_nbrs=[[] for i in range(self.size)]
		self.q=args.q
		self.p=args.p
		self.record=[]

		#self.getLayer2neighbor()
	def reinitialize(self):
		self.visnode=np.zeros((self.size,),dtype=np.bool)
		self.visprob=[[] for i in range(self.size)]
		self.visneigh=[[] for i in range(self.size)]
		self.lay2_nbrs=[[] for i in range(self.size)]
		self.visweight=[[] for i in range(self.size)]

	def getLayer2neighbor(self):
		for node in self.G.nodes():

			stlay1_nbrs = list(self.G.neighbors(node))
			stlay2_nbrs = []
			for nbr in stlay1_nbrs:
				stlay2_nbrs += list(self.G.neighbors(nbr))
			self.lay2_nbrs[node]=stlay2_nbrs
	def returnGraph(self):
		return self.G

	def getWeight(self,cur,nbr,time):
		culWeight=0;
		for i in range(len(self.G[cur][nbr])):
			cur_time=self.G[cur][nbr][i]['time']
			if cur_time<time:
				culWeight+= self.G[cur][nbr][i]['weight'] * math.exp(cur_time-time)
		if culWeight==0:
			return -1
		else:
			return culWeight * self.decay

	def get_walk(self,start_node,time):
		walk = [start_node]
		validwalk = []

		while len(validwalk) < args.walk_length:

				cur = walk[-1]
				cur_nbrs = self.G.neighbors(cur)
				if len(walk) == 1:
					for nbr in cur_nbrs:
						val_nbrs = []
						val_weight = []

						weight=self.getWeight(cur,nbr,time)
						if weight != -1:
							val_nbrs.append(nbr)
							val_weight.append(weight)

						val_index=[i for i in range(len(val_nbrs))]
							#val_weight.append(cur_weight * decay * math.exp(cur_time-time))
					if len(val_nbrs) == 0:
						break
					norm_const = sum(val_weight)
					normalized_probs = [float(u_prob)/norm_const for u_prob in val_weight]
					index = np.random.choice(val_index, 1, normalized_probs)
					next=val_nbrs[index[0]]
					edge_weight=val_weight[index[0]]
					self.record.append(cur)
					self.visnode[cur]=True
					self.visprob[cur]=normalized_probs
					self.visneigh[cur]=val_nbrs
					self.visweight[cur]=val_weight
					walk.append(next)
					if next != start_node:

						validwalk.append(str(edge_weight)+' '+str(next)+' ')

				else:
					val_weight = []
					pre = walk[-2]
					val_nbrs=[]
					normalized_probs=[]
					if self.visnode[cur]:

						normalized_probs = self.visprob[cur]
						val_nbrs=self.visneigh[cur]
						val_weight=self.visweight[cur]
					else:
						for nbr in cur_nbrs:
							weight=self.getWeight(cur,nbr,time)
							if weight == -1:
								continue
							val_nbrs.append(nbr)
							if nbr == pre:
								#nbr is the previous node in the walk
								val_weight.append(1/self.p * weight)
							else:
								if  self.G.has_edge(nbr, pre):
									val_weight.append(weight)

								else:
									val_weight.append(1/self.q * weight)

						#if len(val_nbrs) == 0:
						#		break

						norm_const = sum(val_weight)
						normalized_probs = [float(u_prob)/norm_const for u_prob in val_weight]
						self.record.append(cur)
						self.visnode[cur] = True
						self.visprob[cur]=normalized_probs
						self.visneigh[cur]=val_nbrs
						self.visweight[cur]=val_weight

					val_index=[i for i in range(len(val_nbrs))]
					index = np.random.choice(val_index, 1, normalized_probs)
					#print ("index:",str(index[0])," len nbrs:",str(len(val_nbrs))," len weight:",str(len(val_weight)))
					next=val_nbrs[index[0]]
					edge_weight=val_weight[index[0]]

					walk.append(next)
					if next != start_node:

						validwalk.append(str(edge_weight)+' '+str(next)+' ')

		if len(validwalk) < args.walk_length:
			diff = args.walk_length - len(validwalk)
			stlay1_nbrs = list(self.G.neighbors(start_node))
			stlay2_nbrs = []
			for nbr in stlay1_nbrs:
				stlay2_nbrs.extend(list(self.G.neighbors(nbr)))
			layer1 = np.random.choice(stlay1_nbrs, int(diff * args.portion), replace=True)
			layer2 = np.random.choice(stlay2_nbrs, diff - int(diff * args.portion), replace=True)
			for node in layer1:

				validwalk.append('1 '+str(node)+' ')

			for node in layer2:

				validwalk.append('1 '+str(node)+' ')

		return validwalk

	def getHead(self,st,en,time):
		head=[]
		head.append(str(st)+' ')
		head.append(str(en)+' ')
		head.append(str(self.contextsize)+' ')
		head.append(str(time)+' - ')
		return head

	def getSentence(self,st,en):
			content = []
			count=0
			processed=0
			for edge in self.G.edges(data=True):
				count+=1
				if (count >=st) and (count <=en):
					processed+=1
					print (mp.current_process(),'workload left:',en-st+1,'-',processed,'=',en-st+1-processed,' batch_num:',self.batch_num)
					time=edge[2]['time']
					sentence1 = []
					sentence2 = []
					sentence=self.getHead(edge[0],edge[1],time)
					for iter in range(args.num_walks):
						walk1=self.get_walk(edge[0],time)
						walk2=self.get_walk(edge[1],time)
						sentence1.extend(walk1)
						sentence1.append('; ')
						sentence2.extend(walk2)
						sentence2.append('; ')
					sentence1[-1] = '$ '
					sentence2[-1]='\n'

					sentence1.extend(sentence2)
					sentence.extend(sentence1)
					content.append(sentence)

					for node in self.record:
						self.visnode[node] = False
						self.visprob[node] = []
						self.visneigh[node] =[]
						self.visweight[node] =[]
					self.record=[]

			return content
def caller(indexList,file,num_walks,walk_length,decay,q,p,batch_num):
	model=Walker(num_walks,walk_length,decay,q,p,batch_num)
	model.G = nx.MultiGraph()
	model.batch_num=batch_num
	st=indexList[0]
	en=indexList[-1]
	print (mp.current_process(),'start_index :',st,' end_index :',en)
	index=0
	for line in open(file) :
			strlist = line.split()
			n1 = int(strlist[0])
			n2 = int(strlist[1])
			time = float(strlist[2])
			model.G.add_edge(n1, n2, weight=1, time=time)

	model.size=model.G.size()
	model.reinitialize()
	content=model.getSentence(st,en)
	return content
def main(args):

	index=0
	indexList=[]
	for line in open(args.input) :
		index+=1
		indexList.append(index)
	batch_num=args.batch_num
	batches= [list(c) for c in mit.divide(batch_num, indexList)]
	del indexList
	cpu=args.cpu
	print ('cpu count: ',cpu)

	truncBatches=[]
	for batch in batches:
		truncBatch=[]
		for c in mit.divide(cpu, batch):
			temp= list(c)
			truncBatch.append([temp[0],temp[-1]])
		truncBatches.append(truncBatch)
	del batches
	gc.collect()

	count=0

	for truncBatch in truncBatches:
		count+=1
		pool = mp.Pool(processes=cpu)
		prod_x=partial(caller,file=args.input,num_walks=args.num_walks,walk_length=args.walk_length,
		decay=args.decay,q=args.q,p=args.p,batch_num=count)
		res = pool.map(prod_x, truncBatch)
		pool.close()
		pool.join()
		with open(args.output, 'a') as f:
			for content in res:
				for sentence in content:
					if(len(sentence)>0):
						sentence = ''.join(sentence)
						f.write(sentence)
		del res
		gc.collect()

if __name__ == "__main__":
	args = parse_args()
	main(args)


from tkinter import *
import random

rt=Tk()
root = Tk()
root.title("GUI 1")
rt.title("GUI 2")
root.minsize(250, 200)
rt.minsize(250, 200)

def start():
    myLabel=Label(rt,text="started,jack status check, see result on GUI1")
    myLabel.pack()

def jack_status():
    myLabel=Label(root,text="jack status is okay, now click on GUI2 to check power status")
    myLabel.pack()

def power_status():
    myLabel=Label(rt,text="power is on now, now click on GUI1 to check tray status")
    myLabel.pack()

def tray_status():
    r=IntVar()
    myLabel=Label(root,text="tray status fine, choose from following, and then GUI2 for speed")
    myLabel.pack()
    Radiobutton(root, text="small", variable=r, value=1).pack()
    Radiobutton(root, text="medium", variable=r, value=2).pack()
    Radiobutton(root, text="large", variable=r, value=3).pack()

def speed_status():
    a=IntVar()
    myLabel=Label(rt,text="choose from following speed options")
    myLabel.pack()
    Radiobutton(rt, text="low", variable=a, value=4).pack()
    Radiobutton(rt, text="medium", variable=a, value=5).pack()
    Radiobutton(rt, text="high", variable=a, value=6).pack()

def error_status():
    myLabel1=Label(root,text="starting belt")
    myLabel2=Label(root,text="starting arm")
    myLabel3=Label(root,text="checking other errors")
    myLabel4=Label(root,text="checking air fault status")
    myLabel5=Label(root,text="air fault doesn't exist, all well")
    myLabel6=Label(root,text="checking axis controller fault")
    myLabel7=Label(root,text="checking critical conveyer motor fault")
    myLabel8=Label(root,text="checking critical fault emergency stop")
    myLabel9=Label(root,text="everything is fine, no errors found")

    myLabel1.pack()
    myLabel2.pack()
    myLabel3.pack()
    myLabel4.pack()
    myLabel5.pack()
    myLabel6.pack()
    myLabel7.pack()
    myLabel8.pack()
    myLabel9.pack()

def no_of_pots():
    a=IntVar()
    myLabel=Label(rt,text="choose the number of cups")
    myLabel.pack()
    Radiobutton(rt, text="number of cups is 1", variable=a, value=7).pack()
    Radiobutton(rt, text="number of cups is 2", variable=a, value=8).pack()
    Radiobutton(rt, text="number of cups is 3", variable=a, value=9).pack()
    Radiobutton(rt, text="number of cups is 4", variable=a, value=10).pack()
    Radiobutton(rt, text="number of cups is 5", variable=a, value=11).pack()
    Radiobutton(rt, text="number of cups is 6", variable=a, value=12).pack()
    Radiobutton(rt, text="number of cups is 7", variable=a, value=13).pack()
    Radiobutton(rt, text="number of cups is 8", variable=a, value=14).pack()
    Radiobutton(rt, text="number of cups is 9", variable=a, value=15).pack()
    Radiobutton(rt, text="number of cups is 10", variable=a, value=16).pack()

def start_process():
    myLabel1=Label(root,text="7 medium sized cup has been selected for high speed")
    myLabel2=Label(root,text="7 medium sized cup has arrived at the end of conveyer belt")
    myLabel1.pack()
    myLabel2.pack()

button11 = Button(rt,text="press START to start",command=start)
button1 = Button(root,text="jack status",command=jack_status)
button22 = Button(rt,text="power button status",command=power_status)
button2 = Button(root,text="tray status",command=tray_status)
button33 = Button(rt,text="speed status",command=speed_status)
button3 = Button(root,text="checking errors",command=error_status)
button44 = Button(rt,text="no of pots",command=no_of_pots)
button4=Button(root,text="start process",command=start_process)

button11.pack()
button22.pack()
button1.pack()
button2.pack()
button3.pack()
button33.pack()
button44.pack()
button4.pack()
root.mainloop()
rt.mainloop()