import datetime, logging, re, signal, sys, time, traceback

try:
    import msvcrt
    windows = True
except ModuleNotFoundError:
    windows = False

logger = logging.getLogger("Plex Meta Manager")

class TimeoutExpired(Exception):
    pass

class Failed(Exception):
    pass

def retry_if_not_failed(exception):
    return not isinstance(exception, Failed)

seperating_character = "="
screen_width = 100

method_alias = {
        "actors": "actor", "role": "actor", "roles": "actor",
        "content_ratings": "content_rating", "contentRating": "content_rating", "contentRatings": "content_rating",
        "countries": "country",
        "decades": "decade",
        "directors": "director",
        "genres": "genre",
        "studios": "studio", "network": "studio", "networks": "studio",
        "producers": "producer",
        "writers": "writer",
        "years": "year"
    }
filter_alias = {
    "actor": "actors",
    "audio_language": "audio_language",
    "collection": "collections",
    "content_rating": "contentRating",
    "country": "countries",
    "director": "directors",
    "genre": "genres",
    "max_age": "max_age",
    "originally_available": "originallyAvailableAt",
    "original_language": "original_language",
    "rating": "rating",
    "studio": "studio",
    "subtitle_language": "subtitle_language",
    "writer": "writers",
    "video_resolution": "video_resolution",
    "year": "year"
}
days_alias = {
    "monday": 0, "mon": 0, "m": 0,
    "tuesday": 1, "tues": 1, "tue": 1, "tu": 1, "t": 1,
    "wednesday": 2, "wed": 2, "w": 2,
    "thursday": 3, "thurs": 3, "thur": 3, "thu": 3, "th": 3, "r": 3,
    "friday": 4, "fri": 4, "f": 4,
    "saturday": 5, "sat": 5, "s": 5,
    "sunday": 6, "sun": 6, "su": 6, "u": 6
}
pretty_days = {
    0: "Monday",
    1: "Tuesday",
    2: "Wednesday",
    3: "Thursday",
    4: "Friday",
    5: "Saturday",
    6: "Sunday"
}
pretty_months = {
    1: "January",
    2: "February",
    3: "March",
    4: "April",
    5: "May",
    6: "June",
    7: "July",
    8: "August",
    9: "September",
    10: "October",
    11: "November",
    12: "December"
}
pretty_seasons = {
    "winter": "Winter",
    "spring": "Spring",
    "summer": "Summer",
    "fall": "Fall"
}
pretty_names = {
    "anidb_id": "AniDB ID",
    "anidb_relation": "AniDB Relation",
    "anidb_popular": "AniDB Popular",
    "imdb_list": "IMDb List",
    "imdb_id": "IMDb ID",
    "mal_id": "MyAnimeList ID",
    "mal_all": "MyAnimeList All",
    "mal_airing": "MyAnimeList Airing",
    "mal_upcoming": "MyAnimeList Upcoming",
    "mal_tv": "MyAnimeList TV",
    "mal_ova": "MyAnimeList OVA",
    "mal_movie": "MyAnimeList Movie",
    "mal_special": "MyAnimeList Special",
    "mal_popular": "MyAnimeList Popular",
    "mal_favorite": "MyAnimeList Favorite",
    "mal_season": "MyAnimeList Season",
    "mal_suggested": "MyAnimeList Suggested",
    "mal_userlist": "MyAnimeList Userlist",
    "plex_all": "Plex All",
    "plex_collection": "Plex Collection",
    "plex_search": "Plex Search",
    "tautulli_popular": "Tautulli Popular",
    "tautulli_watched": "Tautulli Watched",
    "tmdb_collection": "TMDb Collection",
    "tmdb_collection_details": "TMDb Collection",
    "tmdb_company": "TMDb Company",
    "tmdb_discover": "TMDb Discover",
    "tmdb_keyword": "TMDb Keyword",
    "tmdb_list": "TMDb List",
    "tmdb_list_details": "TMDb List",
    "tmdb_movie": "TMDb Movie",
    "tmdb_movie_details": "TMDb Movie",
    "tmdb_network": "TMDb Network",
    "tmdb_now_playing": "TMDb Now Playing",
    "tmdb_person": "TMDb Person",
    "tmdb_popular": "TMDb Popular",
    "tmdb_show": "TMDb Show",
    "tmdb_show_details": "TMDb Show",
    "tmdb_top_rated": "TMDb Top Rated",
    "tmdb_trending_daily": "TMDb Trending Daily",
    "tmdb_trending_weekly": "TMDb Trending Weekly",
    "trakt_list": "Trakt List",
    "trakt_trending": "Trakt Trending",
    "trakt_watchlist": "Trakt Watchlist",
    "tvdb_list": "TVDb List",
    "tvdb_movie": "TVDb Movie",
    "tvdb_show": "TVDb Show"
}
mal_ranked_name = {
    "mal_all": "all",
    "mal_airing": "airing",
    "mal_upcoming": "upcoming",
    "mal_tv": "tv",
    "mal_ova": "ova",
    "mal_movie": "movie",
    "mal_special": "special",
    "mal_popular": "bypopularity",
    "mal_favorite": "favorite"
}
mal_season_sort = {
    "anime_score": "anime_score",
    "anime_num_list_users": "anime_num_list_users",
    "score": "anime_score",
    "members": "anime_num_list_users"
}
mal_pretty = {
    "anime_score": "Score",
    "anime_num_list_users": "Members",
    "list_score": "Score",
    "list_updated_at": "Last Updated",
    "anime_title": "Title",
    "anime_start_date": "Start Date",
    "all": "All Anime",
    "watching": "Currently Watching",
    "completed": "Completed",
    "on_hold": "On Hold",
    "dropped": "Dropped",
    "plan_to_watch": "Plan to Watch"
}
mal_userlist_sort = {
    "score": "list_score",
    "list_score": "list_score",
    "last_updated": "list_updated_at",
    "list_updated": "list_updated_at",
    "list_updated_at": "list_updated_at",
    "title": "anime_title",
    "anime_title": "anime_title",
    "start_date": "anime_start_date",
    "anime_start_date": "anime_start_date"
}
mal_userlist_status = [
    "all",
    "watching",
    "completed",
    "on_hold",
    "dropped",
    "plan_to_watch"
]
pretty_ids = {
    "anidbid": "AniDB",
    "imdbid": "IMDb",
    "mal_id": "MyAnimeList",
    "themoviedb_id": "TMDb",
    "thetvdb_id": "TVDb",
    "tvdbid": "TVDb"
}
all_lists = [
    "anidb_id",
    "anidb_relation",
    "anidb_popular",
    "imdb_list",
    "imdb_id",
    "mal_id",
    "mal_all",
    "mal_airing",
    "mal_upcoming",
    "mal_tv",
    "mal_ova",
    "mal_movie",
    "mal_special",
    "mal_popular",
    "mal_favorite",
    "mal_season",
    "mal_suggested",
    "mal_userlist",
    "plex_collection",
    "plex_search",
    "tautulli_popular",
    "tautulli_watched",
    "tmdb_collection",
    "tmdb_collection_details",
    "tmdb_company",
    "tmdb_discover",
    "tmdb_keyword",
    "tmdb_list",
    "tmdb_list_details",
    "tmdb_movie",
    "tmdb_movie_details",
    "tmdb_network",
    "tmdb_now_playing",
    "tmdb_popular",
    "tmdb_show",
    "tmdb_show_details",
    "tmdb_top_rated",
    "tmdb_trending_daily",
    "tmdb_trending_weekly",
    "trakt_list",
    "trakt_trending",
    "trakt_watchlist",
    "tvdb_list",
    "tvdb_movie",
    "tvdb_show"
]
collectionless_lists = [
    "sort_title", "content_rating",
    "summary", "tmdb_summary", "tmdb_description", "tmdb_biography",
    "collection_order", "plex_collectionless",
    "url_poster", "tmdb_poster", "tmdb_profile", "file_poster",
    "url_background", "file_background",
    "name_mapping", "label", "label_sync_mode"
]
other_attributes = [
    "schedule",
    "sync_mode",
    "template",
    "test",
    "tmdb_person"
]
dictionary_lists = [
    "filters",
    "mal_season",
    "mal_userlist",
    "plex_collectionless",
    "plex_search",
    "tautulli_popular",
    "tautulli_watched",
    "tmdb_discover"
]
plex_searches = [
    "actor", #"actor.not", # Waiting on PlexAPI to fix issue
    "country", #"country.not",
    "decade", #"decade.not",
    "director", #"director.not",
    "genre", #"genre.not",
    "producer", #"producer.not",
    "studio", #"studio.not",
    "writer", #"writer.not"
    "year" #"year.not",
]
show_only_lists = [
    "tmdb_network",
    "tmdb_show",
    "tmdb_show_details",
    "tvdb_show"
]
movie_only_lists = [
    "tmdb_collection",
    "tmdb_collection_details",
    "tmdb_movie",
    "tmdb_movie_details",
    "tmdb_now_playing",
    "tvdb_movie"
]
movie_only_searches = [
    "actor", "actor.not",
    "country", "country.not",
    "decade", "decade.not",
    "director", "director.not",
    "producer", "producer.not",
    "writer", "writer.not"
]
tmdb_searches = [
    "actor", "actor.not",
    "director", "director.not",
    "producer", "producer.not",
    "writer", "writer.not"
]
count_lists = [
    "anidb_popular",
    "mal_all",
    "mal_airing",
    "mal_upcoming",
    "mal_tv",
    "mal_ova",
    "mal_movie",
    "mal_special",
    "mal_popular",
    "mal_favorite",
    "mal_suggested",
    "tmdb_popular",
    "tmdb_top_rated",
    "tmdb_now_playing",
    "tmdb_trending_daily",
    "tmdb_trending_weekly",
    "trakt_trending"
]
tmdb_lists = [
    "tmdb_collection",
    "tmdb_collection_details",
    "tmdb_company",
    "tmdb_discover",
    "tmdb_keyword",
    "tmdb_list",
    "tmdb_list_details",
    "tmdb_movie",
    "tmdb_movie_details",
    "tmdb_network",
    "tmdb_now_playing",
    "tmdb_popular",
    "tmdb_show",
    "tmdb_show_details",
    "tmdb_top_rated",
    "tmdb_trending_daily",
    "tmdb_trending_weekly"
]
tmdb_type = {
    "tmdb_collection": "Collection",
    "tmdb_collection_details": "Collection",
    "tmdb_company": "Company",
    "tmdb_keyword": "Keyword",
    "tmdb_list": "List",
    "tmdb_list_details": "List",
    "tmdb_movie": "Movie",
    "tmdb_movie_details": "Movie",
    "tmdb_network": "Network",
    "tmdb_person": "Person",
    "tmdb_show": "Show",
    "tmdb_show_details": "Show"
}
all_filters = [
    "actor", "actor.not",
    "audio_language", "audio_language.not",
    "collection", "collection.not",
    "content_rating", "content_rating.not",
    "country", "country.not",
    "director", "director.not",
    "genre", "genre.not",
    "max_age",
    "originally_available.gte", "originally_available.lte",
    "original_language", "original_language.not",
    "rating.gte", "rating.lte",
    "studio", "studio.not",
    "subtitle_language", "subtitle_language.not",
    "video_resolution", "video_resolution.not",
    "writer", "writer.not",
    "year", "year.gte", "year.lte", "year.not"
]
movie_only_filters = [
    "audio_language", "audio_language.not",
    "country", "country.not",
    "director", "director.not",
    "original_language", "original_language.not",
    "subtitle_language", "subtitle_language.not",
    "video_resolution", "video_resolution.not",
    "writer", "writer.not"
]
boolean_details = [
    "add_to_arr",
    "show_filtered",
    "show_missing",
    "save_missing"
]
all_details = [
    "sort_title", "content_rating",
    "summary", "tmdb_summary", "tmdb_description", "tmdb_biography",
    "collection_mode", "collection_order",
    "url_poster", "tmdb_poster", "tmdb_profile", "file_poster",
    "url_background", "file_background",
    "name_mapping", "add_to_arr", "arr_tag", "label",
    "show_filtered", "show_missing", "save_missing"
]
discover_movie = [
    "language", "with_original_language", "region", "sort_by",
    "certification_country", "certification", "certification.lte", "certification.gte",
    "include_adult",
    "primary_release_year", "primary_release_date.gte", "primary_release_date.lte",
    "release_date.gte", "release_date.lte", "year",
    "vote_count.gte", "vote_count.lte",
    "vote_average.gte", "vote_average.lte",
    "with_cast", "with_crew", "with_people",
    "with_companies",
    "with_genres", "without_genres",
    "with_keywords", "without_keywords",
    "with_runtime.gte", "with_runtime.lte"
]
discover_tv = [
    "language", "with_original_language", "timezone", "sort_by",
    "air_date.gte", "air_date.lte",
    "first_air_date.gte", "first_air_date.lte", "first_air_date_year",
    "vote_count.gte", "vote_count.lte",
    "vote_average.gte", "vote_average.lte",
    "with_genres", "without_genres",
    "with_keywords", "without_keywords",
    "with_networks", "with_companies",
    "with_runtime.gte", "with_runtime.lte",
    "include_null_first_air_dates",
    "screened_theatrically"
]
discover_movie_sort = [
    "popularity.asc", "popularity.desc",
    "release_date.asc", "release_date.desc",
    "revenue.asc", "revenue.desc",
    "primary_release_date.asc", "primary_release_date.desc",
    "original_title.asc", "original_title.desc",
    "vote_average.asc", "vote_average.desc",
    "vote_count.asc", "vote_count.desc"
]
discover_tv_sort = [
    "vote_average.desc", "vote_average.asc",
    "first_air_date.desc", "first_air_date.asc",
    "popularity.desc", "popularity.asc"
]

def adjust_space(old_length, display_title):
    display_title = str(display_title)
    space_length = old_length - len(display_title)
    if space_length > 0:
        display_title += " " * space_length
    return display_title

def make_ordinal(n):
    n = int(n)
    suffix = ["th", "st", "nd", "rd", "th"][min(n % 10, 4)]
    if 11 <= (n % 100) <= 13:
        suffix = "th"
    return str(n) + suffix

def choose_from_list(datalist, description, data=None, list_type="title", exact=False):
    if len(datalist) > 0:
        if len(datalist) == 1 and (description != "collection" or datalist[0].title == data):
            return datalist[0]
        message = "Multiple {}s Found\n0) {}".format(description, "Create New Collection: {}".format(data) if description == "collection" else "Do Nothing")
        for i, d in enumerate(datalist, 1):
            if list_type == "title":
                if d.title == data:
                    return d
                message += "\n{}) {}".format(i, d.title)
            else:
                message += "\n{}) [{}] {}".format(i, d[0], d[1])
        if exact:
            return None
        print_multiline(message, info=True)
        while True:
            try:
                selection = int(logger_input("Choose {} number".format(description))) - 1
                if selection >= 0:                                          return datalist[selection]
                elif selection == -1:                                       return None
                else:                                                       logger.info("Invalid {} number".format(description))
            except IndexError:                                          logger.info("Invalid {} number".format(description))
            except TimeoutExpired:
                if list_type == "title":
                    logger.warning("Input Timeout: using {}".format(data))
                    return None
                else:
                    logger.warning("Input Timeout: using {}".format(datalist[0][1]))
                    return datalist[0][1]
    else:
        return None

def get_list(data, lower=False, split=True):
    if isinstance(data, list):      return data
    elif isinstance(data, dict):    return [data]
    elif split is False:            return [str(data)]
    elif lower is True:             return [d.strip().lower() for d in str(data).split(",")]
    else:                           return [d.strip() for d in str(data).split(",")]

def get_int_list(data, id_type):
    values = get_list(data)
    int_values = []
    for value in values:
        try:                        int_values.append(regex_first_int(value, id_type))
        except Failed as e:         logger.error(e)
    return int_values

def get_year_list(data, method):
    values = get_list(data)
    final_years = []
    current_year = datetime.datetime.now().year
    for value in values:
        try:
            if "-" in value:
                year_range = re.search("(\\d{4})-(\\d{4}|NOW)", str(value))
                start = year_range.group(1)
                end = year_range.group(2)
                if end == "NOW":
                    end = current_year
                if int(start) < 1800 or int(start) > current_year:      logger.error("Collection Error: Skipping {} starting year {} must be between 1800 and {}".format(method, start, current_year))
                elif int(end) < 1800 or int(end) > current_year:        logger.error("Collection Error: Skipping {} ending year {} must be between 1800 and {}".format(method, end, current_year))
                elif int(start) > int(end):                             logger.error("Collection Error: Skipping {} starting year {} cannot be greater then ending year {}".format(method, start, end))
                else:
                    for i in range(int(start), int(end) + 1):
                        final_years.append(i)
            else:
                year = re.search("(\\d+)", str(value)).group(1)
                if int(start) < 1800 or int(start) > current_year:
                    logger.error("Collection Error: Skipping {} year {} must be between 1800 and {}".format(method, year, current_year))
                else:
                    if len(str(year)) != len(str(value)):
                        logger.warning("Collection Warning: {} can be replaced with {}".format(value, year))
                    final_years.append(year)
        except AttributeError:
            logger.error("Collection Error: Skipping {} failed to parse year from {}".format(method, value))
    return final_years

def logger_input(prompt, timeout=60):
    if windows:                             return windows_input(prompt, timeout)
    elif hasattr(signal, "SIGALRM"):        return unix_input(prompt, timeout)
    else:                                   raise SystemError("Input Timeout not supported on this system")

def alarm_handler(signum, frame):
    raise TimeoutExpired

def unix_input(prompt, timeout=60):
    prompt = "| {}: ".format(prompt)
    signal.signal(signal.SIGALRM, alarm_handler)
    signal.alarm(timeout)
    try:            return input(prompt)
    finally:        signal.alarm(0)

def old_windows_input(prompt, timeout=60, timer=time.monotonic):
    prompt = "| {}: ".format(prompt)
    sys.stdout.write(prompt)
    sys.stdout.flush()
    endtime = timer() + timeout
    result = []
    while timer() < endtime:
        if msvcrt.kbhit():
            result.append(msvcrt.getwche())
            if result[-1] == "\n":
                out = "".join(result[:-1])
                logger.debug("{}{}".format(prompt[2:], out))
                return out
        time.sleep(0.04)
    raise TimeoutExpired

def windows_input(prompt, timeout=5):
    sys.stdout.write("| {}: ".format(prompt))
    sys.stdout.flush()
    result = []
    start_time = time.time()
    while True:
        if msvcrt.kbhit():
            chr = msvcrt.getwche()
            if ord(chr) == 13: # enter_key
                out = "".join(result)
                print("")
                logger.debug("{}: {}".format(prompt, out))
                return out
            elif ord(chr) >= 32: #space_char
                result.append(chr)
        if (time.time() - start_time) > timeout:
            print("")
            raise TimeoutExpired

def print_multiline(lines, info=False, warning=False, error=False, critical=False):
    for i, line in enumerate(str(lines).split("\n")):
        if critical:        logger.critical(line)
        elif error:         logger.error(line)
        elif warning:       logger.warning(line)
        elif info:          logger.info(line)
        else:               logger.debug(line)
        if i == 0:
            logger.handlers[1].setFormatter(logging.Formatter(" " * 65 + "| %(message)s"))
    logger.handlers[1].setFormatter(logging.Formatter("[%(asctime)s] %(filename)-27s %(levelname)-10s | %(message)s"))

def print_stacktrace():
    print_multiline(traceback.format_exc())

def my_except_hook(exctype, value, tb):
    for line in traceback.format_exception(etype=exctype, value=value, tb=tb):
        print_multiline(line, critical=True)

def get_id_from_imdb_url(imdb_url):
    match = re.search("(tt\\d+)", str(imdb_url))
    if match:           return match.group(1)
    else:               raise Failed("Regex Error: Failed to parse IMDb ID from IMDb URL: {}".format(imdb_url))

def regex_first_int(data, id_type, default=None):
    match = re.search("(\\d+)", str(data))
    if match:
        return int(match.group(1))
    elif default:
        logger.warning("Regex Warning: Failed to parse {} from {} using {} as default".format(id_type, data, default))
        return int(default)
    else:
        raise Failed("Regex Error: Failed to parse {} from {}".format(id_type, data))

def remove_not(method):
    return method[:-4] if method.endswith(".not") else method

def get_centered_text(text):
    if len(text) > screen_width - 2:
        raise Failed("text must be shorter then screen_width")
    space = screen_width - len(text) - 2
    if space % 2 == 1:
        text += " "
        space -= 1
    side = int(space / 2)
    return "{}{}{}".format(" " * side, text, " " * side)

def seperator(text=None):
    logger.handlers[0].setFormatter(logging.Formatter("%(message)-{}s".format(screen_width - 2)))
    logger.handlers[1].setFormatter(logging.Formatter("[%(asctime)s] %(filename)-27s %(levelname)-10s %(message)-{}s".format(screen_width - 2)))
    logger.info("|{}|".format(seperating_character * screen_width))
    if text:
        logger.info("| {} |".format(get_centered_text(text)))
        logger.info("|{}|".format(seperating_character * screen_width))
    logger.handlers[0].setFormatter(logging.Formatter("| %(message)-{}s |".format(screen_width - 2)))
    logger.handlers[1].setFormatter(logging.Formatter("[%(asctime)s] %(filename)-27s %(levelname)-10s | %(message)-{}s |".format(screen_width - 2)))

def print_return(length, text):
    print(adjust_space(length, "| {}".format(text)), end="\r")
    return len(text) + 2

def print_end(length, text=None):
    if text:        logger.info(adjust_space(length, text))
    else:           print(adjust_space(length, " "), end="\r")


# Sudoku Killer/Sandwich Calculator

#   This program will calculate all possible combinations that a pool of digits add or multiply to a given number

import itertools                            # Import library needed for calculating all combinations
import math                                 # Import library for calculating product of all elements in an iterable

totalNum = ""                               # The number to sum/multiple to
totalPrompt = False                         # Track if user was prompted to enter the total, yet
poolList = [1, 2, 3, 4, 5, 6, 7, 8, 9]      # The pool of numbers to sum/multiply
excludePrompt = False                       # Track if user was prompted to exclude, yet
excludeConf = ""                            # Yes/no if numbers should be excluded from pool
excludeTemp = ""                            # Temporary storage of numbers to exclude
excludelist = ""                            # The numbers we want to exclude from the pool
multList = ""                               # The list of combinations that multiply to numFinal
operConf = ""                               # Choice of operation to complete at end of program
operPrompt = False                          # Track if user entered valid operation

# This function adds up all combinations of digits in pool and prints all that add to total
def summate(total, pool):

    sumsList = [""]                         # The list of combinations that sum to numFinal

    sums = itertools.chain(itertools.combinations(pool, r=n) for n in range(1,len(pool)+1))

    for it in  sums:
        for s in it:
            #print ( f"sum{s} = {s if isinstance(s,int) else sum(s)}")
            if sum(s) == total:
                sumsList.append(s)

    print(sumsList)

# This function multiplies all combinations of digits in pool and prints all that multiply to total
def multimate(total, pool):

    multiList = [""]                            # The list of combinations that multiply to numFinal

    products = itertools.chain(itertools.combinations(pool, r=n) for n in range(1,len(pool)+1))

    for it in  products:
        for s in it:
            if math.prod(s) == total:
                multiList.append(s)

    print(multiList)

# Ask user for the final number to sum/mult to and check if its a valid entry
while totalNum.isnumeric() == False or totalNum == 0:

    if totalPrompt == False: # The first prompt

        totalNum = input("Please enter the non-negative whole number you want to sum/multiply to: ")

        totalPrompt = True

    else: # Subsequent prompts

        totalNum = input("Invalid entry. Please enter a non-negative whole number: ")

        totalPrompt = True

totalNum = int(totalNum) # Typecast the total to an integer for comparing later

while excludePrompt == False:

    print("The current pool:", poolList) # Display the current pool before each prompt

    excludeTemp = input("Enter a digit to exclude from the pool (enter 0 to continue): ")

    if excludeTemp.isnumeric() == True: # Test if the input is a positive whole number

        if excludeTemp == "0": # If input is 0, exit loops and continue with program

            excludePrompt = True
            excludeConf = "no"

        elif int(excludeTemp) in poolList: # If the input is in the current pool list, remove it

            excludeTemp = int(excludeTemp)
            poolList.remove(excludeTemp)

        elif int(excludeTemp) not in poolList: # If input isn't found in the pool, prompt again

            print("Entry not found in the pool.")

    else: print("Invalid entry.")

while operPrompt == False:
    operConf = input("Please enter what operation you would like to use (Sum, Multiply, Both): ")

    if operConf.lower() == "sum":

        summate(totalNum, poolList)
        operPrompt = True

    elif operConf.lower() == "multiply":

        multimate(totalNum, poolList)
        operPrompt = True

    elif operConf.lower() == "both":

        summate(totalNum, poolList)
        multimate(totalNum, poolList)
        operPrompt = True


import numpy as np
import  matplotlib.pyplot as plt #类似 MATLAB 中绘图函数的相关函数
import tensorflow.compat.v1 as tf
import tensorflow.compat.v1 as tf #导入tensorflow，并且使用低版本
tf.compat.v1.disable_eager_execution() #确保Session中的run()函数可以正常运行

count=100
data=[]

for i in range(count):
    x1=np.random.normal(0.00,0.55)
    y1=x1*0.1+0.3+np.random.normal(0.00,0.03)
    data.append([x1,y1])

x_data=[v[0] for v in data]
y_data=[v[1] for v in data]

plt.scatter(x_data,y_data,c='r')
plt.show()

w=tf.Variable(tf.random_uniform([1],-1.0,1.0),name='w')
b=tf.Variable(tf.zeros([1]),name='b')

y=w*x_data+b

loss=tf.reduce_mean(tf.square(y-y_data),name='loss')

#way=tf.train.GradientDescentOptimizer(0.5)

train=tf.train.GradientDescentOptimizer(0.1).minimize(loss,name='train')

sess=tf.Session()

init=tf.global_variables_initializer()
sess.run(init)

for step in range(100):
    sess.run(train)

temp_1=sess.run(w)
temp_2=sess.run(b)

print("y=",temp_1[0],"x+",temp_2[0],",loss=",sess.run(loss))

plt.scatter(x_data,y_data,c='r')
plt.plot(x_data,sess.run(w)*x_data+sess.run(b))
plt.show()


"""empty message

Revision ID: 07d1a2807aca
Revises: 1ab971d5de27
Create Date: 2017-12-12 13:27:01.834759

"""

# revision identifiers, used by Alembic.
revision = '07d1a2807aca'
down_revision = '1ab971d5de27'

from alembic import op
import sqlalchemy as sa

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('risk_types',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('type', sa.String(length=128), nullable=True),
    sa.Column('user', sa.String(), nullable=True),
    sa.PrimaryKeyConstraint('id')
    )
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table('risk_types')
    # ### end Alembic commands ###


from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.core.files.storage import default_storage
from . import util
from .forms import newPageForm
import re
import random

def index(request):
    return render(request, "encyclopedia/index.html", {
        "entries": util.list_entries(),
    })

def randomPage(request):
    entry_list = util.list_entries()
    entry_len = len(entry_list)
    entry_rand = random.randint(1,entry_len)
    rand_entry = entry_list[entry_rand-1]

    return redirect("/wiki/" + rand_entry)

def entry(request, title):
    if request.method == "POST":
        form=newPageForm(request.POST)

        if form.is_valid():
            pageTitle=form.cleaned_data["title"]
            pageContent=form.cleaned_data["content"]
            util.save_entry(pageTitle, pageContent)
            return redirect("/wiki/"+ pageTitle)
    else:
        page_content=util.get_entry(title)
        if page_content:
            final_content=processContent(page_content)
            return render(request, "encyclopedia/entry.html", {
                "content":final_content,
                "title":title
            })
        else:
            return render(request, "encyclopedia/error.html", {
                "title" : title,
                "entries": util.list_entries()
            })

def newpage(request):
    form = newPageForm(initial={
        "title": "New Page",
        "content": ""
        })
    return render(request, "encyclopedia/newpage.html",{
        "form":form,
        "title":"New Page",
        "content":" "
    })

def edit(request):
    title=request.GET['edit']
    content=util.get_entry(title)

    form = newPageForm({"title": title, "content":content})

    return render(request, "encyclopedia/edit.html", {
        "form":form,
        "title":title,
        "content":content
        })

def search(request):
    title=request.GET['search']

    try:
        content = util.get_entry(title)
        content = processContent(content)
        return render(request, "encyclopedia/entry.html", {
            "content":content,
            "title":title
        })

    except:
        results = util.list_entries()
        match_list = []
        l_title = title.lower()
        for r in results:
            rl = r.lower()
            if rl.startswith(l_title):
                match_list.append(r)

        return render(request, "encyclopedia/searchresults.html", {
            "title" : title,
            "match_list" : match_list
        })

def searchresults(request, title, match_list):
    return render(request, "encyclopedia/searchresults.html", {
        "title":title,
        "match_list":match_list
    })

# I don't know how well this approach would scale for large files...
def processContent(content):

    #paragraphs
    content = re.sub('(^[A-Za-z].+$)', r'
\1
', content, flags=re.MULTILINE)
    #headings
    content = re.sub('(##)(.+)',r'
\2
', content)
    content = re.sub('(#[^#])(.+)', r'
\2
', content)
    #strong
    content = re.sub('(\*\*)([^*]+)(\*\*)', r'\2', content)
    #href
    content = re.sub('(\[)([^]]+)(\])(\()([^)]*)(\))', r'\2', content)
    #ul
    spl=content.splitlines()
    srange = len(spl)

    for line in range(srange):
        spl[line] = spl[line].strip()
        if spl[line].startswith("* "):
            spl[line] = "
" + spl[line].replace("* ", "") + "
"

    for line in range(srange):

        if spl[line].startswith("
"):
            if not(spl[line-1].startswith ("
")):
                if not(spl[line-1].startswith("
")):
                    spl[line] = "
" + spl[line]
            # If last line of file is list element, add closing

            if line == srange-1:
                spl[line] += "
"
            elif not(spl[line+1].endswith("
")):
                if not(spl[line+1].endswith("
")):
                    spl[line] = spl[line] + "
"

    content = ("")
    for line in spl:
        content+=line

    return(content)


"""Module to get cities and dates that are available for flight"""
import requests
from lxml import html

URL = 'https://www.airblue.com/'

HEADERS = {'Pragma': 'no-cache',
           'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; tv:11.0) like Gecko',
           'Content-length': '0',
           'Connection': 'Keep-Alive',
           'Host': 'www.airblue.com'}

TREE = html.fromstring(requests.get(URL, headers=HEADERS, params=None).text)

def get_lists_of_available_cities(direction):
    """get list of cities from website that available for flight in to- or from- direction"""
    available_cities = []
    directions = {'from': 1, 'to': 2}
    option_cities = TREE.xpath(
        '//form[@method="get"]'
        '/span[@class="fieldset cities"]/select[{}]/option'.format(directions[direction]))
    for city in option_cities:
        available_cities.append(city.get('value'))
    return available_cities

def get_lists_of_available_dates(direction):
    """get list of dates from website that available for returning"""
    available_dates = []
    option_dates = TREE.xpath(
        '//div[@class="fieldset dates"]/div[@class="{}"]/select/option'.format(direction))
    for date in option_dates:
        value = date.get('value')
        if value is not None:
            available_dates.append(value)
    return available_dates


import cv2
from collections import Counter
from module import findnameoflandmark,findpostion,speak
import math

cap = cv2.VideoCapture(0)
tip=[8,12,16,20]
tipname=[8,12,16,20]
fingers=[]
finger=[]

while True:
         ret, frame = cap.read()
         frame1 = cv2.resize(frame, (640, 480))

         a=findpostion(frame1)
         b=findnameoflandmark(frame1)
         #print(b)

         if len(b and a)!=0:
            finger=[]
            fingers_up = []
            if a[2][1:] < a[4][1:]:
               finger.append(1)
               fingers_up.append(b[4])
               #print (b[4])

            else:
               finger.append(0)

            fingers=[]

            for id in range(0,4):
                if a[tip[id]][2:] < a[tip[id]-2][2:]:
                   #print(b[tipname[id]])
                   fingers_up.append(b[tipname[id]])

                   fingers.append(1)

                else:
                   fingers.append(0)
            if(len(fingers_up) == 0):
                print("STOP")
            elif(len(fingers_up) == 1):
                if('THUMB TIP' in fingers_up):
                    print("MOVE UP")
            elif(len(fingers_up) == 2):
                if(all(i in fingers_up for i in ['THUMB TIP','INDEX FINGER TIP'])):
                    print("MOVE LEFT")
                elif(all(i in fingers_up for i in ['THUMB TIP','PINKY TIP'])):
                    print("MOVE RIGHT")
            elif(len(fingers_up) == 3):
                if(all(i in fingers_up for i in ['MIDDLE FINGER TIP','RING FINGER TIP','PINKY TIP'])):
                    print("MOVE DOWN")
         x=fingers + finger
         c=Counter(x)
         up=c[1]
         down=c[0]
    #     print('This many fingers are up - ', up)
    #     print('This many fingers are down - ', down)

         cv2.imshow("Frame", frame1);
         key = cv2.waitKey(1) & 0xFF

         if key == ord("q"):
            speak("you have"+str(up)+"fingers up  and"+str(down)+"fingers down")

         if key == ord("s"):
           break
cv2.destroyAllWindows()


"""
This is a simple test file for working out how to use PyQt5 for our Schrodinger's Hack project.

This file simply creates a window application with a status bar (with a message).

Author: Kondapuram Aditya Seshadri
Date: October 24, 2020
"""

import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QDesktopWidget

# A class for the application window inheriting QMainWindow
class MainWindow(QMainWindow):
    # run at initialization, runs initialization of QMainWindow and calls initUI()
    def __init__(self):
        super().__init__()
        self.initUI()

    # initUI alters the UI elements on screen
    def initUI(self):
        # Creates bottom text status bar
        self.statusBar().showMessage('Ready')

        # changes the windows size and displays the window
        self.setGeometry(0, 0, 1440, 1080)
        self.show()

# Runs at initialization of file
def main():
    app = QApplication(sys.argv)
    win = MainWindow()

    # exits safely
    sys.exit(app.exec_())

# runs main() at initialization
if __name__ == '__main__':
    main()


import argparse
import glob
import os

from PIL import Image

def make_gifs(results_folder, type):
    results = results_folder  # "data_linear_upsampling_colorspace_stolen_discriminator_results"
    type = type  # "generated"

    # filepaths
    fp_in = f"{results}/{type}/gen.*.png"
    fp_out = f"{results}/gif/{type}/epochs.gif"

    os.makedirs(f"{results}/gif/{type}", exist_ok=True)

    # https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif
    imgs = (Image.open(f) for f in sorted(glob.glob(fp_in)))
    img = next(imgs)  # extract first image from iterator
    img.save(fp=fp_out, format='GIF', append_images=imgs,
             save_all=True, duration=200, loop=0)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Gif maker parameters')
    parser.add_argument('--results', type=str, required=True)
    parser.add_argument('--type', type=str, required=True)

    args = parser.parse_args()

    make_gifs(args.results, args.type)


#Projeto 2 - Construindo um dashboard
#'Previsão do preço de ações (NASDAQ)'

# Bibliotecas
import time
import pandas as pd
import numpy as np

import cufflinks as cf
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots

from pandas_datareader.data import DataReader
from pandas_datareader.nasdaq_trader import get_nasdaq_symbols

import datetime as dt
import streamlit as st

from fbprophet import Prophet
from fbprophet.plot import plot_plotly

import warnings

from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
#init_notebook_mode(connected=True)
cf.go_offline()

# Parametrizações ##################################################
#sns.set_style('whitegrid')
#plt.style.use("fivethirtyeight")
st.set_option('deprecation.showPyplotGlobalUse', False)
#plt.rcParams['axes.facecolor'] = 'white'

# Funções #########################################################
#@st.cache
def plot_candlestick(df, acao):
    load_state.text('Loading graphic candlestick...')
    fig = go.Figure(data=
        [go.Candlestick(x=df.index,
                        open=df["Open"],
                        high=df["High"],
                        low=df["Low"],
                        close=df["Close"])]
    )
    fig.update_layout(
        title=f"Value of {acao}",
        yaxis_title="Price ($)"
    )
    st.plotly_chart(fig)
    return

def plot_line(df, company_name):
    load_state.text('Loading graphic line...')
    year_min = df.Year.min()
    year_max = df.Year.max()
    fig = px.line(df,
                  x=df.index,
                  y="Adj Close",
                  title= f'{company_name} - Stock price ({year_min} - {year_max})',
                  labels={'x':'Year','y':'Price'}
                 )
    st.plotly_chart(fig)
    return

def plot_bar(df, company_name):
    load_state.text('Loading graphic bar...')
    dfbar=df.groupby('Year')['Adj Close'].mean()
    fig = px.bar(dfbar,
                 x=dfbar.index,
                 y=dfbar.values,
                 title = f'{company_name} - Average Value',
                 labels={'x':'Year','y':'Price'}
                )
    st.plotly_chart(fig)
    return

def plot_bubble(acao, company_name):
    load_state.text('Loading graphic bubble...')
    dfbb = df_dict[acao].reset_index()
    dfbb = dfbb.loc[dfbb['Year']==dfbb.Year.max(),['Date','Adj Close','Volume','Year','Month']]
    fig = px.scatter(dfbb,
                     x="Date",
                     y="Adj Close",
                     labels={'x':'Year','y':'Price'},
                     size='Volume',
                     color='Month',
                     title = f'{company_name} - Stock price'
                    )
    st.plotly_chart(fig)
    return

def plot_box(df, company_name):
    load_state.text('Loading graphic boxplot...')
    fig = px.box(df,
                 x="Year",
                 y="Adj Close",
                 title = f'{company_name} - Boxplot Stock price',
                 labels={'x':'Year','y':'Price'}
                )
    st.plotly_chart(fig)
    return

def plot_hist(df, company_name):
    load_state.text('Loading graphic histogram...')
    year_min = df.Year.min()
    year_max = df.Year.max()
    fig = px.histogram(df, x="Adj Close",
                      title= f'{company_name} - Stock price ({year_min} - {year_max})',
                      labels={'x':'Year','y':'Price'})
    st.plotly_chart(fig)
    return

def plot_area(df, company_name):
    load_state.text('Loading graphic area...')
    year_min = df.Year.min()
    year_max = df.Year.max()
    fig = px.area(y=df["Adj Close"],
                  x=df.index,
                  title= f'{company_name} - Stock price ({year_min} - {year_max})',
                  labels={'x':'Year','y':'Price'})
    fig.update_layout(showlegend = False)
    st.plotly_chart(fig)
    return

def plot_cufflinks(df, company_name):
    load_state.text('Loading graphic "cufflinks"...')
    columns = ["High", "Low", "Open", "Close", "Volume"]
    year_min = df.Year.min()
    year_max = df.Year.max()
    fig = df[columns].iplot(
                asFigure=True,
                xTitle="Date",
                yTitle="Price",
                title=f'{company_name} - ({year_min} - {year_max})')
    st.plotly_chart(fig)
    return

def make_forecast(acao, period):
    load_state.text(f'{acao} - Processing ML prophet (forecast calculations)...')
    df = df_dict[acao].reset_index()
    df_train = df[["Date", "Close"]]
    df_train = df_train.rename(columns={'Date': 'ds', 'Close': 'y'})
    m = Prophet()
    m.fit(df_train)
    future = m.make_future_dataframe(periods=period)
    forecast = m.predict(future)
    return m, forecast

# Side Bar #######################################################
project_title = st.sidebar.text_input(label="Project title",
                                      value="Forecast stock calculations")

dt_end = dt.datetime.now().date()
dt_start = st.sidebar.date_input('Start date', dt.date(dt_end.year - 4, 1, 1))
dt_end = st.sidebar.date_input('End date')

n_years = st.sidebar.slider('Years of forecast', 1, 4, 1)
period = n_years * 365

# Criando a lista de ações da Nasdaq para multipla seleção
symbols = get_nasdaq_symbols()
acoes = symbols["NASDAQ Symbol"]

# Selecionando várias ações selecionadas
acoes_selected = st.sidebar.multiselect('Select stocks', acoes)
mask_acoes = symbols["NASDAQ Symbol"].isin(acoes_selected)
filtro_acoes = mask_acoes > 0
acao_list = mask_acoes[filtro_acoes].index.values.tolist()

run_button = st.sidebar.button(label='Execute')

# BODY ################################################################################################################
st.title(project_title)

if run_button:
    if len(acao_list) == 0:
        data_load_state = st.text('Please select stocks...')
    else:
        # Define a data final para o periodo de download das ações
        dt_end = dt.datetime.now().date()

        # Verifica se a data inicial da previsão é compatível, deve ter pelo menos 1 ano para efetuar a previsão
        # Se a data final for menor ou igual a data inicial a data inicial será decrescida em 1 ano
        if dt_end <= dt_start:
            dt_start = dt.datetime(dt_end.year - 4, dt_end.month, dt_end.day).strftime('%Y-%m-%d')

        data_load_state = st.text('Downloading information...')
        load_state = st.text('')

        my_bar = st.progress(0)
        percent_complete = 0

        company_list = list()

        #Efetuando o download dos dados financeiros yahoo e criando os dataframes
        df_dict = dict()
        for acao in acao_list:
            load_state.text(f'Download: {acao}')
            try:
                df_dict[acao] = DataReader(acao, 'yahoo', dt_start, dt_end)
                df_dict[acao]["Year"] = pd.DatetimeIndex(df_dict[acao].index).year
                df_dict[acao]["Month"] = pd.DatetimeIndex(df_dict[acao].index).month

                filtro = symbols["NASDAQ Symbol"]==acao
                acao_company = symbols.loc[filtro, "Security Name"].values[0]
                acao_company = acao_company.split('Common Stock', 1)[0]
                acao_company = acao_company.split('-', 1)[0]
                company_list.append(acao_company)
                load_state.text(f'Information {acao} successfully updated!')

                percent_complete += (0.2/len(acao_list))
                my_bar.progress(percent_complete)

            except:
                load_state.text (f'Information {acao} not found!')
                percent_complete += (0.2/len(acao_list))
                my_bar.progress(percent_complete)

        data_load_state.text('Creating graphics')
        load_state.text('')

        for i, acao in enumerate(acao_list, 1):
            try:
                company_name = company_list[i - 1]
                new_title = f'
{acao} - {company_name}
'
                st.markdown(new_title, unsafe_allow_html=True)
                st.write()

                plot_cufflinks(df_dict[acao], company_name)
                percent_complete += (0.1/len(acao_list))
                my_bar.progress(percent_complete)

                plot_bubble(acao, company_name)
                percent_complete += (0.1/len(acao_list))
                my_bar.progress(percent_complete)

                #plot_hist(df_dict[acao], company_name)

                plot_area(df_dict[acao], company_name)
                percent_complete += (0.1/len(acao_list))
                my_bar.progress(percent_complete)

                plot_bar(df_dict[acao], company_name)
                percent_complete += (0.1/len(acao_list))
                my_bar.progress(percent_complete)

                plot_box(df_dict[acao], company_name)
                percent_complete += (0.1/len(acao_list))
                my_bar.progress(percent_complete)

                #plot_line(df_dict[acao], company_name)
                #plot_candlestick(df_dict[acao], acao)

                m, forecast = make_forecast(acao, period)
                st.subheader(f'FB Prophet forecast to {acao} from {period} days')
                fig_forecast = plot_plotly(m, forecast)
                st.plotly_chart(fig_forecast)
                percent_complete += (0.3/len(acao_list))
                my_bar.progress(round(percent_complete,2))

                #st.subheader(f'Explaining the characteristics of the forecast model')
                #fig_components = m.plot_components(forecast)
                #st.write(fig_components)
            except:
                new_title = f'
{acao}
'
                st.markdown(new_title, unsafe_allow_html=True)
                st.write()

                load_state.text (f'Information {acao} not found!')
                percent_complete += (0.8/len(acao_list))
                my_bar.progress(round(percent_complete,2))

                except_title = f"
Sorry, we can't find the download information.
"
                st.markdown(except_title, unsafe_allow_html=True)
                st.write()

        data_load_state.text('Prediction created!')
        #data_load_state.text('')
        load_state.text('')


#!/usr/bin/env python3

from os import environ

from setuptools import setup

ptr_params = {
    "entry_point_module": "ansible_shed/main",
    "test_suite": "ansible_shed.tests.base",
    "test_suite_timeout": 300,
    "required_coverage": {
        "ansible_shed/main.py": 49,
        "ansible_shed/shed.py": 40,
    },
    "run_black": True,
    "run_flake8": True,
    "run_mypy": True,
    "run_usort": True,
}

ext_modules = []
if "MYPYC_BUILD" in environ:
    print("mypyc build time ...")
    from mypyc.build import mypycify

    ext_modules = mypycify(
        [
            "ansible_shed/__init__.py",
            "ansible_shed/main.py",
            "ansible_shed/shed.py",
        ],
        verbose=True,
    )

setup(
    name="ansible_shed",
    version="2023.3.15",
    description=(
        "asyncio ansible tower like shed to run playbooks and have prometheus "
        + "collector stats"
    ),
    packages=["ansible_shed", "ansible_shed.tests"],
    ext_modules=ext_modules,
    url="http://github.com/cooperlees/ansible_shed/",
    author="Cooper Lees",
    author_email="me@cooperlees.com",
    classifiers=[
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3 :: Only",
        "Programming Language :: Python :: 3.10",
        "Programming Language :: Python :: 3.11",
        "Development Status :: 3 - Alpha",
    ],
    entry_points={"console_scripts": ["ansible-shed = ansible_shed.main:main"]},
    install_requires=["aioprometheus[aiohttp]", "click", "GitPython"],
    extras_require={
        # If you'd like the ansible toolset dependency installed
        "ansible": ["ansible"],
    },
    test_require=["ptr"],
    python_requires=">=3.10",
    test_suite=ptr_params["test_suite"],
)


# importing the Class
from btree import TreeNode

from lvt import levelOrderTraversal

import collections

# function to insert Node
def insertNode(root, value):
    if root is None:
        root = TreeNode(value)
        return root

    myqueue = collections.deque()
    myqueue.append(root)

    while myqueue:
        currNode = myqueue.popleft()
        if currNode is not None:
            if currNode.left is not None:
                myqueue.append(currNode.left)
            else:
                currNode.left = TreeNode(value)
                return root

        if currNode.right is not None:
            myqueue.append(currNode.right)
        else:
            currNode.right = TreeNode(value)
            return root

# def insertNode2(leftnode,rightnode,value):
#     # if root is None:
#     #     root = TreeNode(value)
#     #     return root
#     if leftnode.left is None:
#         leftnode.left = TreeNode(value)
#         return leftnode
#     elif rightnode.right is None:
#         rightnode.right = TreeNode(value)
#         return rightnode
#     else:
#         insertNode2(leftnode.left,rightnode.right,value)

def main():
    root = TreeNode(1)
    root.left = TreeNode(2)
    root.right = TreeNode(6)
    root.left.left = TreeNode(4)
    root.left.right = TreeNode(9)
    # root = None
    print(levelOrderTraversal(root))
    print("Inserting node now")
    print(levelOrderTraversal(insertNode(root,10)))
    #print(insertNode(root,10))
    # levelOrderTraversal(root)

if __name__ == "__main__":
    main();


# Author: Caden Kroonenberg
# Date: 11-29-21

import csv
import data.info as info
import tweepy

# Init twitter user
CONSUMER_KEY = info.CONSUMER_KEY
CONSUMER_SECRET = info.CONSUMER_SECRET
ACCESS_KEY = info.ACCESS_KEY
ACCESS_SECRET = info.ACCESS_SECRET
BEARER_TOKEN = info.BEARER_TOKEN

# Your username
username = info.USERNAME

auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_KEY, ACCESS_SECRET)
api = tweepy.API(auth)
client = tweepy.Client(BEARER_TOKEN, CONSUMER_KEY, CONSUMER_SECRET, ACCESS_KEY, ACCESS_SECRET)

user = client.get_user(username=username)[0]

id = user.id

my_tweets = client.get_users_tweets(id, max_results=25)[0]

for tweet in my_tweets:
    print(str(tweet.id) + '\t' + str(tweet.text))


# ARCHIVO PRINCIPAL
# Autor: Ricardo CÃ¡rdenas Guevara
# Fecha de creaciÃ³n: 17/10/2022

import socket
from encryption_utils import *
from file_utils import *
from input_utils import *
from connection import Connection
from properties import DEFAULT_PORT, SHOW_ENCRYPTED_MESSAGES

encryption_key = generateKey()
listening_port = DEFAULT_PORT
username = socket.gethostname()
remote_username = ''

want_exit = False

# MenÃº principal
# Se sigue mostrando hasta que se elija la opciÃ³n de salir
while not want_exit:
    print('\n====================================')
    print('>>    CHAT CIFRADO CON PYTHON     <<')
    print('====================================')
    print('Usuario: [' + username + ']')
    print('Puerto de escucha: [' + str(listening_port) + ']')
    print('Llave de cifrado: [' + encryption_key.replace('\n', '')[:13] + '...]')
    print('\nOpciones:')
    print('1.- Iniciar chat')
    print('2.- Cambiar nombre de usuario')
    print('3.- Cambiar puerto de escucha')
    print('4.- Generar llave de cifrado')
    print('5.- Importar llave de cifrado')
    print('6.- Exportar llave de cifrado')
    print('7.- Salir')
    option = select_option('\nSelecciona una opciÃ³n:', range(1, 8))
    if option == 1:
        print('\nINICIAR CHAT')
        connection = Connection(listening_port, username)
        try:
            address = readAddress('\nIngresa la direcciÃ³n del usuario remoto:\n')
            loading('Conectando')
            if connection.connect(address):
                remote_username = connection.remote_username
                loaded('Conectado con ' + remote_username)
                print('\nEspera tu turno para enviar un mensaje, escribe /salir para salir del chat')
                if (connection.first):
                    print('\nEnvÃa el primer mensaje')

                    message = input('\n> ')
                    # ValidaciÃ³n de salida del chat
                    if message == '/salir':
                        connection.send('/salir')
                        break
                    encrypted_message = encrypt(message, encryption_key)
                    connection.send(encrypted_message)
                    clear()
                    print('[' + username + ']: ' + message)
                    if SHOW_ENCRYPTED_MESSAGES:
                        print(' ðŸ”’â†“â†“â†“')
                        print('[' + username + ']: ' + encrypted_message)
                while True:
                    print('\nEsperando mensaje...', end='')
                    message = connection.listen()
                    # ValidaciÃ³n de salida del chat
                    if message == '/salir':
                        clear(inline=True)
                        print(remote_username + ' ha abandonado el chat')
                        break
                    decrypted_message = decrypt(message, encryption_key)
                    clear(inline=True)
                    if SHOW_ENCRYPTED_MESSAGES:
                        print('[' + remote_username + ']: ' + message)
                        print(' ðŸ”“â†“â†“â†“')
                    print('[' + remote_username + ']: ' + decrypted_message)

                    message = input('\n> ')
                    # ValidaciÃ³n de salida del chat
                    if message == '/salir':
                        connection.send('/salir')
                        break
                    encrypted_message = encrypt(message, encryption_key)
                    connection.send(encrypted_message)
                    clear()
                    print('[' + username + ']: ' + message)
                    if SHOW_ENCRYPTED_MESSAGES:
                        print(' ðŸ”’â†“â†“â†“')
                        print('[' + username + ']: ' + encrypted_message)

                connection.close()
                alert('Chat finalizado')
            else:
                warning('Error al establecer conexiÃ³n')
        except:
            connection.close()
            alert('Chat finalizado')
    elif option == 2:
        print('\nCAMBIAR NOMBRE DE USUARIO')
        if (confirm_option('\nÂ¿Deseas cambiar tu nombre de usuario? se sobreescribirÃ¡ el nombre actual (' + username + ')')):
            username = input('\nIngresa el nuevo nombre de usuario:\n')
            alert('Nombre cambiado')
        else:
            alert('AcciÃ³n cancelada')
    elif option == 3:
        print('\nCAMBIAR PUERTO DE ESCUCHA')
        if (confirm_option('\nÂ¿Deseas cambiar puerto de escucha? se sobreescribirÃ¡ el puerto actual (' + str(listening_port) + ')')):
            listening_port = readInt('\nIngresa el nuevo nÃºmero de puerto:\n')
            alert('Puerto cambiado')
        else:
            alert('AcciÃ³n cancelada')
    elif option == 4:
        print('\nGENERAR LLAVE DE CIFRADO')
        if (confirm_option('\nÂ¿Deseas generar una nueva llave de cifrado?, esta reemplazarÃ¡ a la llave actual')):
            # GeneraciÃ³n de nueva llave de cifrado
            encryption_key = generateKey()
            alert('Llave de cifrado generada')
        else:
            alert('AcciÃ³n cancelada')
    elif option == 5:
        print('\nIMPORTAR LLAVE DE CIFRADO')
        if (confirm_option('\nÂ¿Deseas importar una llave de cifrado?, esta reemplazarÃ¡ a la llave actual')):
            # ImportaciÃ³n de llave de cifrado desde archivo
            # Se evalÃºa antes de reemplazar la clave en caso de que haya fallado la lectura del archivo
            key = get_encryption_key(input('\nIngresa el nombre del archivo:\n'))
            if key:
                encryption_key = key
                alert('Llave de cifrado importada')
            else:
                warning('No se pudo obtener la llave de cifrado')
        else:
            alert('AcciÃ³n cancelada')
    elif option == 6:
        print('\nEXPORTAR LLAVE DE CIFRADO')
        # Guardado de llave de cifrado en archivo KEY
        filename = input('\nIngresa el nombre del archivo a guardar\n')
        if (save_encryption_key(filename, encryption_key)):
            alert('Llave de cifrado guardada en archivo ' + filename + '.key')
        else:
            warning('No se pudo guardar el archivo')
        print()
    elif option == 7:
        print('\nSALIR')
        if (confirm_option('\nÂ¿Deseas salir del sistema?')):
            want_exit = True
            print('\nBye :)')
        else:
            alert('AcciÃ³n cancelada')


from flask import Response, request
from flask_restful import Resource
from models import Following, User, db
import json
from views import get_authorized_user_ids #added
import flask_jwt_extended

def get_path():
    return request.host_url + 'api/posts/'

class FollowingListEndpoint(Resource):
    def __init__(self, current_user):
        self.current_user = current_user

    @flask_jwt_extended.jwt_required()
    def get(self):
        # return all of the "following" records that the current user is following
        followings = Following.query.filter_by(user_id=self.current_user.id).all()

        body = [following.to_dict_following() for following in followings]

        return Response(json.dumps(body), mimetype="application/json", status=200)

    @flask_jwt_extended.jwt_required()
    def post(self):
        # create a new "following" record based on the data posted in the body
        args = request.get_json()

        if 'user_id' not in args:
            return Response(json.dumps("New following requires user."), mimetype="application/json", status=400)

        try:
            user_id = int(args.get('user_id'))
        except:
            return Response(json.dumps("New following requires user."), mimetype="application/json", status=400)

        requested_user = User.query.get(user_id)
        if not requested_user:
            return Response(json.dumps("No valid users."), mimetype="application/json", status=404)

        authorized_users = get_authorized_user_ids(self.current_user)
        if user_id in authorized_users:
            return Response(json.dumps("Already following user."), mimetype="application/json", status=400)

        new_following = Following(
            following_id = user_id,
            user_id = self.current_user.id
        )

        db.session.add(new_following)
        db.session.commit()

        # body = Following.query.get(new_following.id).to_dict_following()
        body = new_following.to_dict_following()

        return Response(json.dumps(body), mimetype="application/json", status=201)

class FollowingDetailEndpoint(Resource):
    def __init__(self, current_user):
        self.current_user = current_user

    @flask_jwt_extended.jwt_required()
    def delete(self, id):
        # delete "following" record where "id"=id

        following = Following.query.get(id)

        if not following or following.user_id != self.current_user.id:
            return Response(json.dumps("No valid following"), mimetype="application/json", status=404)

        Following.query.filter_by(id=id).delete()
        db.session.commit()

        return Response(json.dumps("Deleted following " + str(id)), mimetype="application/json", status=200)

def initialize_routes(api):
    api.add_resource(
        FollowingListEndpoint,
        '/api/following',
        '/api/following/',
        resource_class_kwargs={'current_user': flask_jwt_extended.current_user}
    )
    api.add_resource(
        FollowingDetailEndpoint,
        '/api/following/<int:id>',
        '/api/following/<int:id>/',
        resource_class_kwargs={'current_user': flask_jwt_extended.current_user}
    )


#!/usr/bin/env python
"""
# SuffolkCycleDjango : Implementation of blog_tags.py

Summary :

Use Case :
    As a <actor> I want <outcome> So that <justification>

Testable Statements :
    Can I <Boolean statement>
    ....
"""

__version__ = "0.1"
__author__ = 'Tony Flury : anthony.flury@btinternet.com'
__created__ = '07 Feb 2016'

from django import template
from django.core.urlresolvers import reverse
from django.utils.html import format_html, mark_safe

register = template.Library()

@register.simple_tag(name='ellipsis')
def add_ellipsis(string, length=30, center=False):
    if not isinstance(string, basestring):
        return ""

    if len(string) <= length:
        return string

    # Make sure that we never exceed designated length and that our two 'halves' don't overlap
    if center:
        stride = min((len(string) - 3) / 2, (length - 3) / 2)
        return string[:stride] + '...' + string[-stride:]
    else:
        return string[:length - 3] + '...'

@register.simple_tag(name='year_visible', takes_context=True)
def year_visible(context):
    if int(context['archive']['display_year']) == int(context['year']['grouper']):
        return mark_safe("archive-visible")
    else:
        return mark_safe('')

@register.simple_tag(name='month_visible', takes_context=True)
def month_visible(context):
    if (int(context['archive']['display_year']) == int(context['year']['grouper'])) and (
                int(context['archive']['display_month']) == int(context['month']['grouper'])):
        return mark_safe("archive-visible")
    else:
        return mark_safe('')

@register.simple_tag(name='year_url', takes_context=True)
def year_url(context):
    year = "{:4d}".format(int(context['year']['grouper']))
    return reverse('blog:Archive', kwargs={'year': year})

@register.simple_tag(name='month_url', takes_context=True)
def month_url(context):
    year = "{:4d}".format(int(context['year']['grouper']))
    month = "{:02d}".format(int(context['month']['grouper']))
    return reverse('blog:Archive', kwargs={'year': year, 'month': month})

def build_url(text, page, context):

    tag = context['args'].get('tag_slug', None)
    year = context['args'].get('year', None)
    month = context['args'].get('month', None)

    if not tag and not year and not month:
        return format_html('{text}',
                            url = reverse('Blog:Home', kwargs={'page':page} ),
                            text = text)

    if tag:
        return format_html('{text}',
                            url = reverse('blog:Search', kwargs={'tag_slug':tag, 'page':page} ),
                            text = text)

    if year and not month:
        return format_html('{text}',
                            url = reverse('blog:Archive', kwargs={'year':year, 'page':page} ),
                            text = text)

    if year and month:
                return format_html('{text}',
                            url = reverse('blog:Archive', kwargs={'year':year, 'month':month, 'page':page} ),
                            text = text)

@register.simple_tag(name='prev_page_url', takes_context=True)
def prev_page_url(context):

    prev_page = context['args'].get('prev_page', None)
    if not prev_page : # Page count starts from one
        return ""

    return build_url('Previous', prev_page, context)

@register.simple_tag(name='next_page_url', takes_context=True)
def next_page_url(context):

    next_page = context['args'].get('next_page', None)
    if not next_page:
        return ""

    return build_url('Next', next_page, context)


import datetime
import time

import cv2
from flask import Blueprint, render_template, request, send_from_directory, session, jsonify, json, Response, redirect
from werkzeug.utils import secure_filename
from app.models.my_data import Images, Cameras, Videos, Events

from ..models import db
from .. import app
import os
from os.path import join, dirname, realpath
import validators

# AI MODELS
import YoloDetector
import EmotionDetector

home = Blueprint('home', __name__)

USER_EMAIL = ""

# PATHS
UPLOADS_PATH = join(dirname(realpath(__file__)), '../static/user_data/uploads_emotion_detection/..')
app.config['UPLOAD_FOLDER'] = UPLOADS_PATH

app_root = os.path.dirname(os.path.abspath(__file__))
target = os.path.join(app_root, '../static/user_data/uploads_object_detection/')
target2 = os.path.join(app_root, '../static/user_data/uploads_emotion_detection/')
if not os.path.isdir(target):
    os.makedirs(target)

if not os.path.isdir(target2):
    os.makedirs(target2)

######################## YOLO VARIABLES ###################################
WEIGHTS = "yolov7.pt"
PRED_LOCATION = os.path.join(app_root, '../static/user_data/predicts_object_detection/')
YOLO = YoloDetector.YoloDetectorClass(project=PRED_LOCATION)
YOLO_LOADED = False
Video_Name = ""
CameraLinks = []

###################### EMOTION VARIABLES #####################################
EMOTION_PATH = "cnn.hdf5"
DETECTION_PATH = "haarcascade_frontalface_default.xml"
EMO_PRED_LOCATION = os.path.join(app_root, '../static/user_data/predicts_emotion_detection/')
EMO = EmotionDetector.EmotionDetectorClass(detection_model_path=DETECTION_PATH, emotion_model_path=EMOTION_PATH,
                                           detected_img_path=EMO_PRED_LOCATION)
EMO_LOADED = False
EMO_Video_Name = ""
EMO_CameraLinks = []

ModelSelected = ""

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

#########################################################  SHOWING LIVE VIDEOS ##############################################################
########################################################## WORKING WITH YOLO ################################################################
##### VIDEO PATH
def infer_video(video_name):
    user_mail = USER_EMAIL

    # Loading YOLO
    global YOLO_LOADED
    if not YOLO_LOADED:
        YOLO.Load_Model()
        YOLO_LOADED = True

    count = 0
    Vid_Path = os.path.join(target, video_name)
    video = cv2.VideoCapture(Vid_Path)
    w = int(video.get(3))
    h = int(video.get(4))

    FPS = 10
    Writer_Path = os.path.join(PRED_LOCATION, video_name)
    Vid_Writer = cv2.VideoWriter(Writer_Path, cv2.VideoWriter_fourcc(*'mp4v'), FPS, (w, h))

    MyVid = Videos.query.filter_by(name=video_name).first()
    Vid_ID = MyVid.id

    Frame_Count = 0
    while True:
        success, frame = video.read()
        if not success:
            break
        else:
            Frame_Location = r'{}/{}__{}.png'.format(PRED_LOCATION, video_name, count)
            cv2.imwrite(Frame_Location, frame)
            det_frame, detections = YOLO.Run_Detect(source=Frame_Location)

            Vid_Writer.write(det_frame)

            ret, buffer = cv2.imencode('.jpg', det_frame)
            frame = buffer.tobytes()
            if detections:
                detections = detections[0]
                detections_splitted = detections.split(',')
                detections = " , ".join(detections_splitted)

                # Adding the Event to the Database
                new_event = Events(email=user_mail, model="Object Detection", source="Video", source_name=video_name,
                                   message=detections, event_date=str(datetime.datetime.now()),
                                   event_link="{}__{}.png".format(video_name, count))
                db.session.add(new_event)
                db.session.commit()

            Frame_Count += 10  # i.e. at 30 fps, this advances one second
            video.set(cv2.CAP_PROP_POS_FRAMES, Frame_Count)

        count += 1

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

@app.route("/videos_feed")
def video_feed():
    if session.get('email') is None:
        login_problem = "Sorry, you have to login first to use our service.."
        return render_template('auth/login.html', login_problem=login_problem)

    else:
        global USER_EMAIL
        USER_EMAIL = session['email']
        return Response(infer_video(Video_Name),
                        mimetype='multipart/x-mixed-replace; boundary=frame')

##### CAMERAS
def Pred_One_Camera(camera_link, CameraLinkName):
    user_mail = USER_EMAIL

    # Loading YOLO
    global YOLO_LOADED
    if not YOLO_LOADED:
        YOLO.Load_Model()
        YOLO_LOADED = True

    video = cv2.VideoCapture(camera_link)
    w = int(video.get(3))
    h = int(video.get(4))
    FPS = 10
    Writer_Path = os.path.join(PRED_LOCATION, CameraLinkName + ".mp4")
    Vid_Writer = cv2.VideoWriter(Writer_Path, cv2.VideoWriter_fourcc(*'mp4v'), FPS, (w, h))
    count = 0
    CamID = Cameras.query.filter_by(link=camera_link).order_by(Cameras.id.desc()).first().id
    print(CamID)
    while True:
        success, frame = video.read()
        if not success:
            break
        else:
            Frame_Location = r'{}/{}__{}.png'.format(PRED_LOCATION, CameraLinkName, count)
            cv2.imwrite(Frame_Location, frame)
            det_frame, detections = YOLO.Run_Detect(source=Frame_Location)
            Vid_Writer.write(det_frame)

            ret, buffer = cv2.imencode('.jpg', det_frame)
            frame = buffer.tobytes()

            if detections:
                detections = detections[0]
                detections_splitted = detections.split(',')
                detections = " , ".join(detections_splitted)
                new_event = Events(email=user_mail, model="Object Detection", source="Camera", source_name=camera_link,
                                   message=detections, event_date=str(datetime.datetime.now()),
                                   event_link="{}__{}.png".format(CameraLinkName, count))

                db.session.add(new_event)
                db.session.commit()

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

@app.route("/cameras_feed/<int:id>/")
def camera_feed(id):
    if session.get('email') is None:
        login_problem = "Sorry, you have to login first to use our service.."
        return render_template('auth/login.html', login_problem=login_problem)
    else:
        global USER_EMAIL
        USER_EMAIL = session['email']
        timestamp = int(time.time())
        CameraLinkName = "CamLink{}_{}".format(id, timestamp)

        if ModelSelected == "Object Detection":
            return Response(Pred_One_Camera(CameraLinks[id], CameraLinkName),
                            mimetype='multipart/x-mixed-replace; boundary=frame')

        elif ModelSelected == "Emotion Detection":
            return Response(Pred_One_Camera_emo(CameraLinks[id], CameraLinkName),
                            mimetype='multipart/x-mixed-replace; boundary=frame')

###################### WORKING WITH EMO ############################
#### VIDEO
def infer_video_emo(video_name):
    user_mail = USER_EMAIL

    # Loading EMO
    global EMO_LOADED
    if not EMO_LOADED:
        EMO.Load_Model()
        EMO_LOADED = True

    count = 0
    Vid_Path = os.path.join(target2, video_name)
    video = cv2.VideoCapture(Vid_Path)
    w = int(video.get(3))
    h = int(video.get(4))
    FPS = 5
    print("111111")
    Writer_Path = os.path.join(EMO_PRED_LOCATION, video_name)
    Vid_Writer = cv2.VideoWriter(Writer_Path, cv2.VideoWriter_fourcc(*'mp4v'), FPS, (w, h))

    MyVid = Videos.query.filter_by(name=video_name).first()
    Vid_ID = MyVid.id

    Frame_Count = 0
    while True:
        success, frame = video.read()
        if not success:
            break
        else:
            Frame_Location = r'{}/{}__{}.png'.format(EMO_PRED_LOCATION, video_name, count)
            cv2.imwrite(Frame_Location, frame)
            Saving_Name = r'{}__{}.png'.format(video_name, count)
            det_frame, detections = EMO.Run_Detect(source=Frame_Location, saving_name=Saving_Name)

            Vid_Writer.write(det_frame)

            ret, buffer = cv2.imencode('.jpg', det_frame)
            frame = buffer.tobytes()
            if detections:
                new_event = Events(email=user_mail, model="Emotion Detection", source="Video", source_name=video_name,
                                   message=detections, event_date=str(datetime.datetime.now()),
                                   event_link="{}__{}.png".format(video_name, count))
                db.session.add(new_event)
                db.session.commit()

            Frame_Count += 10  # i.e. at 30 fps, this advances one second
            video.set(cv2.CAP_PROP_POS_FRAMES, Frame_Count)
        count += 1

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

@app.route("/videos_feed_emo")
def video_feed_emo():
    if session.get('email') is None:
        login_problem = "Sorry, you have to login first to use our service.."
        return render_template('auth/login.html', login_problem=login_problem)
    else:
        global USER_EMAIL
        USER_EMAIL = session['email']
        return Response(infer_video_emo(Video_Name),
                        mimetype='multipart/x-mixed-replace; boundary=frame')

#### CAMERAS
def Pred_One_Camera_emo(camera_link, CameraLinkName):
    user_mail = USER_EMAIL

    # Loading YOLO
    global EMO_LOADED
    if not EMO_LOADED:
        EMO.Load_Model()
        EMO_LOADED = True

    video = cv2.VideoCapture(camera_link)
    w = int(video.get(3))
    h = int(video.get(4))
    FPS = 10

    Writer_Path = os.path.join(EMO_PRED_LOCATION, CameraLinkName + ".mp4")
    Vid_Writer = cv2.VideoWriter(Writer_Path, cv2.VideoWriter_fourcc(*'mp4v'), FPS, (w, h))
    count = 0
    CamID = Cameras.query.filter_by(link=camera_link).order_by(Cameras.id.desc()).first().id

    while True:
        success, frame = video.read()
        if not success:
            break
        else:
            Frame_Location = r'{}/{}__{}.png'.format(EMO_PRED_LOCATION, CameraLinkName, count)
            cv2.imwrite(Frame_Location, frame)
            Saving_Name = r'{}__{}.png'.format(CameraLinkName, count)
            det_frame, detections = EMO.Run_Detect(source=Frame_Location, saving_name=Saving_Name)

            Vid_Writer.write(det_frame)

            ret, buffer = cv2.imencode('.jpg', det_frame)
            frame = buffer.tobytes()

            if detections:
                detections = detections[0]
                new_event = Events(email=user_mail, model="Emotion Detection", source="Camera", source_name=camera_link,
                                   message=detections, event_date=str(datetime.datetime.now()),
                                   event_link="{}__{}.png".format(CameraLinkName, count))

                db.session.add(new_event)
                db.session.commit()

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

######################################################### ROUTES ####################################################
# HOME PAGE
@home.route('/home')
def home_page():
    # Check if user is logged in
    if session.get('email') is None:
        login_problem = "Sorry, you have to login first to use our service.."
        return render_template('auth/login.html', login_problem=login_problem)

    else:
        user_mail = session['email']
        user_fullname = session['fullname']

        # Events Table Data
        table_data = []
        # 1- Getting Events and Storing in the Table of Data
        UserEvents = Events.query.filter_by(email=user_mail)
        for event in UserEvents:
            data = {"ID": event.id, "Model": event.model, "Source": event.source, "Source_Name": event.source_name,
                    "Messages": event.message, "Date": event.event_date, "Link": event.event_link}
            table_data.append(data)

        #############################
        # Solid Line DATA
        solid_labels = []
        solid_data = []
        if len(table_data) > 0:
            min_date = min(table_data, key=lambda x: x['Date'])["Date"]
            max_date = max(table_data, key=lambda x: x['Date'])["Date"]
            current_date = min_date
            while current_date <= max_date:
                events_betn = list(filter(lambda x: min_date <= x['Date'] <= current_date, table_data))
                solid_labels.append(current_date.strftime('%m-%d %H:%M'))
                solid_data.append(len(events_betn))
                current_date = current_date + datetime.timedelta(hours=1)

        solid_dict = {
            "data": solid_data,
            "labels": solid_labels,
            "title": 'Events per Time',
            "data_unit": "Events",
            "min_unit": 0,
            "unit_label": ""
        }

        ################################
        # Score Data
        no_cameras = Cameras.query.filter_by(email=user_mail).count()
        no_videos = Videos.query.filter_by(email=user_mail).count()
        score_dict = {
            "no_events": len(table_data),
            "no_models": 2,
            "no_cameras": no_cameras,
            "no_videos": no_videos
        }
        return render_template("home/home.html",
                               solid_line=solid_dict, score=score_dict, table_data=table_data,
                               myemail=user_mail, fullname=user_fullname)

# Welcome (Login Page)
@home.route('/')
def welcome_page():
    return redirect('/home')

## Page of ANALYTICS (CHOOSING MODEL AND METHOD)
# - Once user choose model --> Model will be Loaded
@home.route('/analytics', methods=['GET', 'POST'])
def analytic_page():
    if session.get('email') is None:
        login_problem = "Sorry, you have to login first to use our service.."
        return render_template('auth/login.html', login_problem=login_problem)

    else:
        user_fullname = session['fullname']
        user_mail = session['email']
        global ModelSelected

        if request.method == 'GET':
            return render_template('home/Analytics.html', myemail=user_mail, fullname=user_fullname)

        else:
            # Choosing YOLO:
            if request.form.get('model') == 'object_detection':
                global YOLO_LOADED
                if not YOLO_LOADED:
                    YOLO.Load_Model()
                    YOLO_LOADED = True
                ModelSelected = "Object Detection"

            elif request.form.get('model') == "emotion_detection":
                global EMO_LOADED
                if not EMO_LOADED:
                    EMO.Load_Model()
                    EMO_LOADED = True
                ModelSelected = "Emotion Detection"

            # Image
            if request.form['source'] == 'image':
                return render_template('home/uploadImage.html', myemail=user_mail, fullname=user_fullname,
                                       model=ModelSelected)
            # Video
            elif request.form['source'] == 'video':
                return render_template('home/uploadvedio.html', myemail=user_mail, fullname=user_fullname,
                                       model=ModelSelected)
            # Camera
            else:
                return render_template('home/uploadcam.html', myemail=user_mail, fullname=user_fullname,
                                       model=ModelSelected)

# Object Detection Page
@home.route('/object_det')
def object_page():
    if session.get('email') is None:
        return render_template('error/notfound.html')
    else:
        myname = session['username']
        myemail = session['email']
        firstname = session['firstname']
        return render_template('home/objectDet.html', myname=myname, myemail=myemail, firstname=firstname)

# Emotion Detection Page
@home.route('/emotion_det')
def emotion_page():
    if session.get('email') == None:
        return render_template('error/notfound.html')
    else:
        myname = session['username']
        myemail = session['email']
        firstname = session['firstname']

        return render_template('home/emotionalDet.html', myname=myname, myemail=myemail, firstname=firstname)

############################################### GETTING FILES SRCs FUNCTIONS #############################
# Static/Upload  --> YOLO UPLOADED FILES
@app.route('/file/<filename>')
def get_image(filename):
    return send_from_directory(target, filename)

# Static2/Upload2  --> EMO UPLOADED FILES
@app.route('/file2/<filename>')
def get_image2(filename):
    return send_from_directory(target2, filename)

# Image PREDICTED Locations
@app.route('/file3/<filename>')
def get_predict(filename):
    if ModelSelected == "Object Detection":
        return send_from_directory(PRED_LOCATION, filename)
    elif ModelSelected == "Emotion Detection":
        return send_from_directory(EMO_PRED_LOCATION, filename)

# Static2/Predicts2  --> EMO PREDICTED FILES
@app.route('/file4/<filename>')
def get_predict2(filename):
    return send_from_directory(EMO_PRED_LOCATION, filename)

######################################################### UPLOADING IMGS, VIDEOS, Picking CAMERAS ###########################################
#### UPLOADING AND DETECTING IMAGE #####
@home.route('/upload_image', methods=['GET', 'POST'])
def upload_image():
    if session.get('email') is None:
        login_problem = "Sorry, you have to login first to use our service.."
        return render_template('auth/login.html', login_problem=login_problem)

    else:
        prediction = 0
        user_fullname = session['fullname']
        user_mail = session['email']

        if request.method == 'GET':
            return render_template('home/uploadImage.html', prediction=prediction, myname=user_fullname,
                                   myemail=user_mail)

        else:
            myimage = request.files['image']
            filename = secure_filename(myimage.filename)
            if ModelSelected == "Object Detection":
                destination = '/'.join([target, filename])
            else:
                destination = '/'.join([target2, filename])

            myimage.save(destination)  # Saved the uploaded image

            if not myimage:
                uploadimg = 'please upload an image'
                return render_template('home/uploadImage.html', prediction=prediction, uploadimg=uploadimg,
                                       myname=user_fullname, myemail=user_mail)

            else:
                # Adding Image to the DB
                filename = secure_filename(myimage.filename)
                mimetype = myimage.mimetype
                newimage = Images(email=user_mail, model=ModelSelected, mimetype=mimetype, name=filename,
                                  img=myimage.read())
                db.session.add(newimage)
                db.session.commit()
                id = newimage.id
                uploaded = 'your image uploaded successfully'
                myimage = Images.query.filter_by(id=id).first()
                filename = myimage.name

                if ModelSelected == "":
                    return render_template("home/Analytics.html", myemail=user_mail, fullname=user_fullname)

                else:
                    prediction = 1
                    detections = ""

                    if ModelSelected == "Object Detection":
                        # Loading YOLO
                        global YOLO_LOADED
                        if not YOLO_LOADED:
                            YOLO.Load_Model(weights=WEIGHTS)
                            YOLO_LOADED = True

                        detected_img, detections = YOLO.Run_Detect(source=destination)
                        if detections:
                            detections = detections[0]
                            detections = detections.split(',')
                        else:
                            detections = ["No Detections"]

                        EventLink = r"predicts_object_detection/{}".format(filename)

                    elif ModelSelected == "Emotion Detection":
                        global EMO_LOADED
                        if not EMO_LOADED:
                            EMO.Load_Model()
                            EMO_LOADED = True
                        detected_img, detections = EMO.Run_Detect(source=destination, saving_name=filename)
                        if detections is None:
                            detections = "No Detections"
                        EventLink = r"predicts_emotion_detection/{}".format(filename)

                    NewEvent = Events(email=user_mail, model=ModelSelected, source="Image", source_name=filename,
                                      event_date=str(datetime.datetime.now()), message=", ".join(detections),
                                      event_link=EventLink)
                    db.session.add(NewEvent)
                    db.session.commit()

                    return render_template('home/uploadImage.html', prediction=prediction, detections=detections,
                                           filename=filename, uploaded=uploaded, myname=user_fullname,
                                           myemail=user_mail)

#### UPLOADING VIDEO
@home.route('/upload_vedio', methods=['GET', 'POST'])
def upload_vedio():
    prediction = 0
    if session.get('email') is None:
        login_problem = "Sorry, you have to login first to use our service.."
        return render_template('auth/login.html', login_problem=login_problem)

    else:
        myname = session['fullname']
        myemail = session['email']

        if request.method == 'GET':
            return render_template('home/uploadvedio.html', prediction=prediction, myname=myname,
                                   myemail=myemail)
        else:
            global Video_Name
            myved = request.files['video']
            filename = secure_filename(myved.filename)
            timestamp = int(time.time())
            [video, extension] = filename.split('.')
            Video_Name = "{}_{}.{}".format(video, timestamp, extension)

            if ModelSelected == "Object Detection":
                destination = '/'.join([target, Video_Name])
            else:
                destination = '/'.join([target2, Video_Name])

            myved.save(destination)
            if not myved:
                uploadvedio = 'please upload a video'
                return render_template('home/uploadvedio.html', prediction=prediction, uploadvedio=uploadvedio,
                                       myname=myname, myemail=myemail)
            else:
                if ModelSelected == "":
                    return render_template("home/Analytics.html", myemail=myemail, fullname=myname)

                else:
                    source_name = secure_filename(myved.filename)
                    NewVideo = Videos(name=Video_Name, email=myemail, model=ModelSelected)
                    db.session.add(NewVideo)
                    db.session.commit()
                    prediction = 1
                    uploaded = 'your video uploaded successfully'

                return render_template('home/uploadvedio.html', prediction=prediction, uploaded=uploaded, myname=myname,
                                       myemail=myemail, model=ModelSelected, source_name=Video_Name)

############# UPLOAD CAMERA LINKS #######################
### YOLO
@home.route('/upload_link', methods=['GET', 'POST'])
def upload_link():
    if session.get('email') is None:
        login_problem = "Sorry, you have to login first to use our service.."
        return render_template('auth/login.html', login_problem=login_problem)

    else:
        myname = session['fullname']
        myemail = session['email']
        flag1 = 0

        if request.method == 'GET':
            return render_template('home/uploadcam.html', flag1=flag1, myname=myname, myemail=myemail)

        else:
            stream_url = request.form['stream_url']
            location = request.form['location']
            camera_name = request.form['camera_name']

            NewCamera = Cameras(email=myemail, link=stream_url, name=camera_name, location=location,
                                model=ModelSelected)
            db.session.add(NewCamera)
            db.session.commit()
            flag1 = 1
            uploaded = 'your link uploaded successfully , add a new one'
            return render_template('home/uploadcam.html', flag1=flag1, uploaded=uploaded, myname=myname,
                                   myemail=myemail)

### LOADING CAMERAS TO PREDICT
## YOLO
@home.route('/predict_link')
def predict_link():
    if session.get('email') is None:
        login_problem = "Sorry, you have to login first to use our service.."
        return render_template('auth/login.html', login_problem=login_problem)

    else:
        myname = session['fullname']
        myemail = session['email']

        MyCameraLinks = Cameras.query.filter_by(email=myemail, model=ModelSelected)
        global CameraLinks
        CameraLinks = []
        for Camera in MyCameraLinks:
            CameraLinks.append(Camera.link)
        return render_template('home/predictcam.html', model=ModelSelected, CamLinks=MyCameraLinks, myemail=myemail,
                               myname=myname)

@home.route('/video_events/<source_name>')
def video_events(source_name):
    myname = session['fullname']
    myemail = session['email']
    return render_template('home/videoEvents.html', myname=myname, myemail=myemail, source_name=source_name)

@home.route('/get_video_events/<source_name>')
def get_video_events(source_name):
    CurrentEvents = Events.query.filter_by(source_name=source_name)

    ids = []
    models = []
    sources = []
    source_names = []
    messages = []
    dates = []
    links = []

    if CurrentEvents:
        for event in CurrentEvents:
            ids.append(event.id)
            models.append(event.model)
            sources.append(event.source)
            source_names.append(event.source_name)
            messages.append(event.message)
            dates.append(event.event_date)
            links.append(event.event_link)

        return jsonify({"IDS": ids,
                        "MODELS": models,
                        "SOURCES": sources,
                        "SOURCE_NAMES": source_names,
                        "MESSAGES": messages,
                        "DATES": dates,
                        "LINKS": links,
                        "error": "data"})
    else:
        return jsonify({"error": "no data"})

@home.route('/camera_events/<int:id>')
def camera_events(id):
    if session.get('email') is not None:
        myname = session['fullname']
        myemail = session['email']

        Camera = Cameras.query.filter_by(id=id).first()
        CamLink = Camera.link
        CamEvents = Events.query.filter_by(source_name=CamLink)
        return render_template('home/cameraEvents.html', myevnts=CamEvents, myname=myname, myemail=myemail, camera_id=id)
    else:
        return render_template('error/notfound.html')

@home.route('/get_camera_events/<int:id>')
def get_camera_events(id):
    Camera = Cameras.query.filter_by(id=id).first()
    CamLink = Camera.link
    CurrentEvents = Events.query.filter_by(source_name=CamLink)

    ids = []
    models = []
    sources = []
    source_names = []
    messages = []
    dates = []
    links = []

    if CurrentEvents:
        for event in CurrentEvents:
            ids.append(event.id)
            models.append(event.model)
            sources.append(event.source)
            source_names.append(event.source_name)
            messages.append(event.message)
            dates.append(event.event_date)
            links.append(event.event_link)

        return jsonify({"IDS": ids,
                        "MODELS": models,
                        "SOURCES": sources,
                        "SOURCE_NAMES": source_names,
                        "MESSAGES": messages,
                        "DATES": dates,
                        "LINKS": links,
                        "error": "data"})
    else:
        return jsonify({"error": "no data"})

@home.route('/deleteCam/<int:id>')
def del_cam(id):
    Camera = Cameras.query.filter_by(id=id).first()
    CamLink = Camera.link

    Events.query.filter_by(source_name=CamLink).delete()
    Cameras.query.filter_by(id=int(id)).delete()
    db.session.commit()
    return redirect("/predict_link")

# STORAGE BUTTON
@home.route('/storage')
def storage():
    print("Opening Storage.....")
    return render_template("home/storage.html")

# All Events
@home.route('/all_events/')
def all_events():
    # Check if user is logged in
    if session.get('email') is None:
        login_problem = "Sorry, you have to login first to use our service.."
        return render_template('auth/login.html', login_problem=login_problem)

    else:
        user_mail = session['email']
        user_fullname = session['fullname']

        # Events Table Data
        table_data = []
        # 1- Getting Events and Storing in the Table of Data
        UserEvents = Events.query.filter_by(email=user_mail)
        for event in UserEvents:
            data = {"ID": event.id, "Model": event.model, "Source": event.source, "Source_Name": event.source_name,
                    "Messages": event.message, "Date": event.event_date, "Link":event.event_link}
            table_data.append(data)

        return render_template("home/all_events.html", table_data=table_data, myemail=user_mail, fullname=user_fullname)


import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore

# Use a service account
cred = credentials.Certificate('returnmeds-bd71b-firebase-adminsdk-3kdmo-d05c72ea7e.json')
firebase_admin.initialize_app(cred)

fdb = firestore.client()

def write_data(doc_name, data):
    fdb.collection('schedule').document(doc_name).set(data)

def read_ongoing_data(username):
    return fdb.collection('schedule').where('username', '==', username).stream()


import fasttext
from tqdm import tqdm_notebook as tqdm
import pickle
from sklearn.metrics import f1_score, accuracy_score, precision_score, recall_score
from config import *

model = fasttext.train_supervised(input=newtrainpath,thread = thread_num,epoch=e_num,lr=lr_num) ##train model
model.save_model("fasttext{}epoch{}lr.bin".format(e_num,lr_num))  ## save model
model = fasttext.load_model("fasttext{}epoch{}lr.bin".format(e_num,lr_num))
nor2len = pickle.load(open(nor2len_path, 'rb'))
num2nor = pickle.load(open(num2labelpath, 'rb'))

def get_diff(h2m, m2l, real_result,predict_result):
    real_h= []
    real_m= []
    real_l= []
    predict_h = []
    predict_m = []
    predict_l = []
    for i in range(len(real_result)):
        t = num2nor[real_result[i]]
        if nor2len[t] < m2l:
            real_l.append(real_result[i])
            predict_l.append(predict_result[i])
        elif nor2len[t] <= h2m:
            real_m.append(real_result[i])
            predict_m.append(predict_result[i])
        else:
            real_h.append(real_result[i])
            predict_h.append(predict_result[i])
    return real_h,real_m,real_l,predict_h,predict_m,predict_l

def getscore(path):
    r_label=[]
    predict=[]
    with open(path,encoding = 'utf-8') as file:
        lines = file.readlines()
        for line in tqdm(lines):
            words = line.split('\t',1)
            result = model.predict(words[0])
            predict.append(int(result[0][0][9:]))
            words[1] = words[1].replace('\n','').replace('__label__','')
            r_label.append(int(words[1]))
    label_h,label_m,label_l,predict_h,predict_m,predict_l = get_diff(20,5,r_label,predict)
    return [accuracy_score(r_label, predict),accuracy_score(label_h, predict_h),accuracy_score(label_m, predict_m),accuracy_score(label_l, predict_l)],[precision_score(r_label, predict,average='macro'),precision_score(label_h, predict_h,average='macro'),precision_score(label_m, predict_m,average='macro'),precision_score(label_l, predict_l,average='macro')],[recall_score(r_label, predict,average='macro'),recall_score(label_h, predict_h,average='macro'),recall_score(label_m, predict_m,average='macro'),recall_score(label_l, predict_l,average='macro')],[f1_score(r_label, predict,average='macro'),f1_score(label_h, predict_h,average='macro'),f1_score(label_m, predict_m,average='macro'),f1_score(label_l, predict_l,average='macro')]

a1,p1,r1,f1 = getscore(newdevpath)
a2,p2,r2,f2 = getscore(newtestpath)

with open('fasttext{}epoch{}lr.txt'.format(e_num,lr_num),'w') as fi:
    fi.write('valid:\n')
    for a,p,r,f in zip(a1,p1,r1,f1):
        fi.write('accuary:'+str(a)+'\n')
        fi.write('precision:'+str(p)+'\n')
        fi.write('recall:'+str(r)+'\n')
        fi.write('f1:'+str(f)+'\n\n')

    fi.write('test:\n')
    for a,p,r,f in zip(a2,p2,r2,f2):
        fi.write('accuary:'+str(a)+'\n')
        fi.write('precision:'+str(p)+'\n')
        fi.write('recall:'+str(r)+'\n')
        fi.write('f1:'+str(f)+'\n\n')

# In[ ]: