## LIBRARY IMPORTS ##
import streamlit as st
import streamlit.components.v1 as components

import pandas as pd
import numpy as np

import plotly as ply
import plotly.express as px
from plotly.subplots import make_subplots
import plotly.graph_objects as go

from PIL import Image
import datetime

from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.preprocessing import MinMaxScaler

# from streamlit_aggrid import AgGrid

# import matplotlib.pyplot as plt
# import seaborn as sns
# import dash as dash
# from dash import dash_table
# from dash import dcc
# from dash import html
# from dash.dependencies import Input, Output
# from dash.exceptions import PreventUpdate
# import dash_bootstrap_components as dbc

# import scipy.stats as stats
# import statistics

## DIRECTORY CONFIGURATION ##
abs_path = r'https://raw.githubusercontent.com/nehat312/winning-composition/main'
players_path = abs_path + '/data/NBA_champs_python.csv'
# team_path = abs_path + '/data/NBA_champs_python.csv'

## DATA IMPORT ##
champion_players = pd.read_csv(players_path, index_col='YR_TM_PLR', header=0)
# champion_teams = pd.read_csv(players_path, header=0, index_col='YR_TM_PLR')

## PRE-PROCESSING ##
# players_path.sort_values(by='disc_year', inplace=True)

# ## TIME INTERVALS ##
# today = datetime.date.today()
# before = today - datetime.timedelta(days=1095) #700
# start_date = '2000-01-01'
# end_date = today

## IMAGE IMPORT ##

## DESIGN IMAGES ##
nba_logo_1 = Image.open('images/NBA_Logo.png')
nba_logo_2 = Image.open('images/NBA_Logo2.png')
court_img_1 = Image.open('images/Court1.png')
capstone_court = Image.open('images/NBA_Court_Trim.png')

## EASTERN CONFERENCE LOGOS ##
East_logo = Image.open('images/east/NBA_East.png')
ATL_logo = Image.open('images/east/ATL-Hawks.png')
BKN_logo = Image.open('images/east/BKN-Nets.png')
BOS_logo = Image.open('images/east/BOS-Celtics.png')
CHI_logo = Image.open('images/east/CHI-Bulls.png')
CHA_logo = Image.open('images/east/CHA-Hornets.png')
CLE_logo = Image.open('images/east/CLE-Cavaliers.png')
DET_logo = Image.open('images/east/DET-Pistons.png')
IND_logo = Image.open('images/east/IND-Pacers.png')
MIA_logo = Image.open('images/east/MIA-Heat.png')
MIL_logo = Image.open('images/east/MIL-Bucks.png')
NYK_logo = Image.open('images/east/NYK-Knicks.png')
ORL_logo = Image.open('images/east/ORL-Magic.png')
PHI_logo = Image.open('images/east/PHI-Sixers.png')
TOR_logo = Image.open('images/east/TOR-Raptors.png')
WAS_logo = Image.open('images/east/WAS-Wizards.png')

## WESTERN CONFERENCE LOGOS ##
West_logo = Image.open('images/west/NBA_West.png')
DAL_logo = Image.open('images/west/DAL-Mavericks.png')
DEN_logo = Image.open('images/west/DEN-Nuggets.png')
GSW_logo = Image.open('images/west/GSW-Warriors.png')
HOU_logo = Image.open('images/west/HOU-Rockets.png')
LAC_logo = Image.open('images/west/LAC-Clippers.png')
LAL_logo = Image.open('images/west/LAL-Lakers.png')
MEM_logo = Image.open('images/west/MEM-Grizzlies.png')
MIN_logo = Image.open('images/west/MIN-Timberwolves.png')
NOP_logo = Image.open('images/west/NOP-Pelicans.png')
PHX_logo = Image.open('images/west/PHX-Suns.png')
POR_logo = Image.open('images/west/POR-Trailblazers.png')
SAC_logo = Image.open('images/west/SAC-Kings.png')
SAS_logo = Image.open('images/west/SAS-Spurs.png')
OKC_logo = Image.open('images/west/OKC-Thunder.png')
UTA_logo = Image.open('images/west/UTA-Jazz.png')

## FORMAT / STYLE ##

## COLOR SCALES ##

Tropic = px.colors.diverging.Tropic
Blackbody = px.colors.sequential.Blackbody
BlueRed = px.colors.sequential.Bluered

Sunsetdark = px.colors.sequential.Sunsetdark
Sunset = px.colors.sequential.Sunset
Temps = px.colors.diverging.Temps
Tealrose = px.colors.diverging.Tealrose

Ice = px.colors.sequential.ice
Ice_r = px.colors.sequential.ice_r
Dense = px.colors.sequential.dense
Deep = px.colors.sequential.deep
PuOr = px.colors.diverging.PuOr
Speed = px.colors.sequential.speed
# IceFire = px.colors.diverging.
# YlOrRd = px.colors.sequential.YlOrRd
# Mint = px.colors.sequential.Mint
# Electric = px.colors.sequential.Electric

# pd.options.display.float_format = '${:,.2f}'.format
# pd.set_option('display.max_colwidth', 200)

## VISUALIZATION LABELS ##

all_cols = ['YR_TM_PLR', 'YEARS', 'YEAR',
            'TEAM', 'CHAMP', 'PLAYER', 'NUMBER',
            'POS', 'WTD POS', 'RD POS',
            'HEIGHT (IN)',
            'WEIGHT (LBS)',
            'BMI', 'W-SPAN (IN)', 'APE',
            'AGE',  'EXPERIENCE',
            'NATION', 'COUNTRY',
            'CONTINENT', 'GLOBAL REGION',
            'CONFERENCE', 'COLLEGE',
            'SALARY', '% SALARY', 'TM TTL SAL', 'NBA SAL CAP', 'NBA TM AVG SAL',
            '$MM/eWIN', '$MM/TmWIN', '$MM/PlrWS',
            'MP', 'PER', 'WTD-PER', 'AGE',
            'TS%', 'AST%', 'STL%', 'BLK%', 'TO%',
            'AST%/TO%', 'STOCK%',
            'D-WS', 'O-WS', 'WS', 'WS_VAL', 'TM-WS',
            'RAPTOR', 'RAPTOR_VAL', 'TM-RAPTOR',
            'LEBRON', 'LEBRON_VAL', 'TM-LEBRON', #D #O
            'USG%', 'TS%',
            ]

viz_cols = ['YEAR', 'TEAM', 'CHAMP', 'PLAYER', 'WTD POS', 'RD POS',
            'HEIGHT (IN)', 'WEIGHT (LBS)', 'BMI', 'W-SPAN (IN)', 'APE',
            'AGE',  'EXPERIENCE',
            'NATION', 'COUNTRY',
            'CONTINENT', 'GLOBAL REGION',
            'CONFERENCE', 'COLLEGE',
            'SALARY', '% SALARY', 'TM TTL SAL', 'NBA SAL CAP', 'NBA TM AVG SAL',
            '$MM/eWIN', '$MM/TmWIN', '$MM/PlrWS',
            'MP', #'PER', 'WTD-PER',
            'USG%', 'TS%', 'AST%', 'STL%', 'BLK%', 'TO%',
            'AST%/TO%', 'STOCK%',
            'D-WS', 'O-WS', 'WS',  'TM-WS', 'TM-RAPTOR', 'TM-LEBRON',
            'RAPTOR', 'LEBRON',

            'RAPTOR_VAL', 'LEBRON_VAL', 'WS_VAL',
            ]

scale_cols = ['PLAYER', 'NUMBER',
            'POS', 'WTD POS', 'RD POS',
            'HEIGHT (IN)',
            'WEIGHT (LBS)',
            'BMI', 'W-SPAN (IN)', 'APE',
            'AGE',  'EXPERIENCE',
            'NATION', 'COUNTRY',
            'CONTINENT', 'GLOBAL REGION',
            'CONFERENCE', 'COLLEGE',
            'RAPTOR', 'WS', #'LEBRON',
            'BMI', 'W-SPAN (IN)', 'APE',
            'AGE', #'EXPERIENCE',
            'USG%', 'TS%', 'AST%', 'STL%', 'BLK%', 'TO%',
            'AST%/TO%', 'STOCK%',
            'SALARY', 'TM TTL SAL',
            'NBA SAL CAP', 'NBA TM AVG SAL',
            '$MM/eWIN', '$MM/TmWIN', '$MM/PlrWS',
            ]

team_df_cols = ['CHAMP', 'PLAYER', 'AGE', 'EXPERIENCE',
                'COUNTRY', 'COLLEGE', #'CONFERENCE',
                 'MP', 'WTD POS',
                'BMI', 'W-SPAN (IN)', 'APE',
                'USG%', 'TS%',
                # 'AST%', 'STL%', 'BLK%', 'TO%',
                'AST%/TO%', 'STOCK%', 'WS',
                'SALARY', 'TM TTL SAL',
                'NBA SAL CAP', 'NBA TM AVG SAL',
                  # 'RAPTOR', #'LEBRON',
                '$MM/eWIN', '$MM/TmWIN', '$MM/PlrWS',
                ]

chart_labels = {'W-SPAN (IN)':'WINGSPAN (IN)',
                'APE':'APE INDEX',
                'WTD POS':'WTD POS',
                'RD POS':'POS',
                'CHAMP':'YR-TM',
                'LEBRON_VAL':'LEBRON/$',
                'RAPTOR_VAL':'RAPTOR/$',
                'SALARY':'SALARY ($)',
                'WS_VAL':'WS/$',
                'TM TTL SAL':'TTL TEAM SALARY',
                'NBA SAL CAP':'NBA SALARY CAP',
                'NBA TM AVG SAL':'AVG NBA TEAM SALARY',
                '1991':'1991-CHI', '1992':'1992-CHI', '1993':'1993-CHI',
                '1994':'1994-HOU', '1995':'1995-HOU',
                '1996':'1996-CHI', '1997':'1997-CHI', '1998':'1998-CHI',
                '1999':'1999-SAS', '2000':'2000-LAL', '2001':'2001-LAL', '2002':'2002-LAL',
                '2003':'2003-SAS', '2004':'2004-DET', '2005':'2005-SAS',
                '2006':'2006-MIA', '2007':'2007-SAS', '2008':'2008-BOS',
                '2009':'2009-LAL', '2010':'2010-LAL',
                '2011':'2011-DAL', '2012':'2012-MIA', '2013':'2013-MIA', '2014':'2014-SAS',
                '2015':'2015-GSW', '2016':'2016-CLE', '2017':'2017-GSW', '2018':'2018-GSW',
                '2019':'2019-TOR', '2020':'2020-LAL', '2021':'2021-MIL', '2022':'2022-GSW',
                # '':'',
                }

team_logos_dict = {'ATL':ATL_logo, 'BKN':BKN_logo, 'BOS':BOS_logo, 'CHI':CHI_logo, 'CHA':CHA_logo,
                   'CLE':CLE_logo, 'DET':DET_logo, 'IND':IND_logo, 'MIL':MIL_logo, 'MIA':MIA_logo,
                   'NYK':NYK_logo, 'ORL':ORL_logo, 'PHI':PHI_logo, 'TOR':TOR_logo, 'WAS':WAS_logo,
                   'DAL':DAL_logo, 'DEN':DEN_logo, 'GSW':GSW_logo, 'HOU':HOU_logo, 'LAC':LAC_logo,
                   'LAL':LAL_logo, 'MEM':MEM_logo, 'MIN':MIN_logo, 'NOP':NOP_logo, 'PHX':PHX_logo,
                   'POR':POR_logo, 'SAC':SAC_logo, 'SAS':SAS_logo, 'OKC':OKC_logo, 'UTA':UTA_logo,
                   }

#https://nbacolors.com/team/washington-wizards-color
#https://teamcolorcodes.com/nba-team-color-codes/
team_colors_dict = {'ATL':['#E03A3E','#C1D32F','#26282A'], 'BKN':['#000000','#FFFFFF'], 'BOS':['#007A33','#007A33'],
                    'CHI':[''], 'CHA':[], 'CLE':[], 'DET':[], 'IND':[], 'MIL':[], 'MIA':[],
                   'NYK':[], 'ORL':[], 'PHI':[], 'TOR':[], 'WAS':[],
                   'DAL':[], 'DEN':[], 'GSW':[], 'HOU':[], 'LAC':[],
                   'LAL':[], 'MEM':[], 'MIN':[], 'NOP':[], 'PHX':[],
                   'POR':[], 'SAC':[], 'SAS':[], 'OKC':[], 'UTA':[],
                   }

## COURT BACKGROUND ##
court_img_dict = dict(source=court_img_1, xref="paper", yref="paper", x=0.5, y=0.5, sizex=2.5, sizey=1,
                      xanchor="center", yanchor="middle", #left right  #top bottom
                      opacity=.35, visible=True, layer="below", # sizing="contain",
                      )

court_img_dict_3D = dict(source=court_img_1, xref="paper", yref="paper", x=0.5, y=0.5, sizex=1.25, sizey=1,
                      xanchor="center", yanchor="middle", #left right  #top bottom
                      opacity=.15, visible=True, layer="below", # sizing="contain",
                      )

## FEATURED VARIABLES ##

team_list = list(champion_players['TEAM'].unique())
champ_list = list(champion_players['CHAMP'].unique())
college_list = list(champion_players['COLLEGE'].unique())
conference_list = list(champion_players['CONFERENCE'].unique())
country_list = list(champion_players['COUNTRY'].unique())
region_list = list(champion_players['GLOBAL REGION'].unique())

team_logos_list = [ATL_logo, BKN_logo, BOS_logo, CHI_logo, CHA_logo,
                    CLE_logo, DET_logo, IND_logo, MIA_logo, MIL_logo,
                    NYK_logo, ORL_logo, PHI_logo, TOR_logo, WAS_logo,
                    DAL_logo, DEN_logo, HOU_logo, LAC_logo, LAL_logo,
                    GSW_logo, MEM_logo, MIN_logo, MEM_logo, PHX_logo,
                    SAS_logo, SAC_logo, OKC_logo, UTA_logo, POR_logo]

eastconf_logos_list = [ATL_logo, BKN_logo, BOS_logo, CHI_logo, CHA_logo,
                       CLE_logo, DET_logo, IND_logo, MIA_logo, MIL_logo,
                       NYK_logo, ORL_logo, PHI_logo, TOR_logo, WAS_logo]

westconf_logos_list = [DAL_logo, DEN_logo, HOU_logo, LAC_logo, LAL_logo,
                       GSW_logo, MEM_logo, MIN_logo, MEM_logo, PHX_logo,
                       SAS_logo, SAC_logo, OKC_logo, UTA_logo, POR_logo]

# champion_players['LOGO'] = champion_players.TEAM.map(team_logos_dict)

#%%
# # group_cols = ['']
# college_raptor = champion_players.groupby(['TEAM', 'COLLEGE']).mean()
# print(college_raptor)

# Keep? Functional?
# champion_players['LOGO'] = champion_players.TEAM.map(team_logos_dict)

## FILTER DATA ##
champion_players = champion_players[viz_cols]
champion_players = champion_players[champion_players['MP'] > 350] #175
lebron_val_players = champion_players[champion_players['YEAR'] >= 2010]

## TO DO / NOTES

#**#value per dollar is the key AKA secret sauce *** #
#DK PTS/MIN
## TABLEAU ##
## NEO4J / MONGO ?? ##
## PAGES OR TABS FOR EACH ROSTER???
## LOG TRANSFORM??
## PCA From test code

# MinMaxScaler

# ss = StandardScaler()
# mms = MinMaxScaler()

# scaled_MP = ss.fit_transform(champion_players['MP'])
# scaled_MP = scaled_MP.reshape(-1,1)
# champion_players['ss_MP'] = scaled_MP
# print(champion_players['ss_MP'])

## GROUP BY CHAMPIONSHIP TEAM

champion_teams = champion_players[team_df_cols]
champion_teams = champion_teams.astype(str)

chi_bulls_1991 = champion_teams[champion_teams['CHAMP'] == '1991-CHI']
chi_bulls_1992 = champion_teams[champion_teams['CHAMP'] == '1992-CHI']
chi_bulls_1993 = champion_teams[champion_teams['CHAMP'] == '1993-CHI']
hou_rockets_1994 = champion_teams[champion_teams['CHAMP'] == '1994-HOU']
hou_rockets_1995 = champion_teams[champion_teams['CHAMP'] == '1995-HOU']
chi_bulls_1996 = champion_teams[champion_teams['CHAMP'] == '1996-CHI']
chi_bulls_1997 = champion_teams[champion_teams['CHAMP'] == '1997-CHI']
chi_bulls_1998 = champion_teams[champion_teams['CHAMP'] == '1998-CHI']
sas_spurs_1999 = champion_teams[champion_teams['CHAMP'] == '1999-SAS']
lal_lakers_2000 = champion_teams[champion_teams['CHAMP'] == '2000-LAL']
lal_lakers_2001 = champion_teams[champion_teams['CHAMP'] == '2001-LAL']
lal_lakers_2002 = champion_teams[champion_teams['CHAMP'] == '2002-LAL']
sas_spurs_2003 = champion_teams[champion_teams['CHAMP'] == '2003-SAS']
det_pistons_2004 = champion_teams[champion_teams['CHAMP'] == '2004-DET']
sas_spurs_2005 = champion_teams[champion_teams['CHAMP'] == '2005-SAS']
mia_heat_2006 = champion_teams[champion_teams['CHAMP'] == '2006-MIA']
sas_spurs_2007 = champion_teams[champion_teams['CHAMP'] == '2007-SAS']
bos_celtics_2008 = champion_teams[champion_teams['CHAMP'] == '2008-BOS']
lal_lakers_2009 = champion_teams[champion_teams['CHAMP'] == '2009-LAL']
lal_lakers_2010 = champion_teams[champion_teams['CHAMP'] == '2010-LAL']
dal_mavs_2011 = champion_teams[champion_teams['CHAMP'] == '2011-DAL']
mia_heat_2012 = champion_teams[champion_teams['CHAMP'] == '2012-MIA']
mia_heat_2013 = champion_teams[champion_teams['CHAMP'] == '2013-MIA']
sas_spurs_2014 = champion_teams[champion_teams['CHAMP'] == '2014-SAS']
gsw_warriors_2015 = champion_teams[champion_teams['CHAMP'] == '2015-GSW']
cle_cavs_2016 = champion_teams[champion_teams['CHAMP'] == '2016-CLE']
gsw_warriors_2017 = champion_teams[champion_teams['CHAMP'] == '2017-GSW']
gsw_warriors_2018 = champion_teams[champion_teams['CHAMP'] == '2018-GSW']
tor_raptors_2019 = champion_teams[champion_teams['CHAMP'] == '2019-TOR']
lal_lakers_2020 = champion_teams[champion_teams['CHAMP'] == '2020-LAL']
mil_bucks_2021 = champion_teams[champion_teams['CHAMP'] == '2021-MIL']
gsw_warriors_2022 = champion_teams[champion_teams['CHAMP'] == '2022-GSW']

champ_df_list = [chi_bulls_1991, chi_bulls_1992, chi_bulls_1993,
                 hou_rockets_1994, hou_rockets_1995,
                 chi_bulls_1996, chi_bulls_1997, chi_bulls_1998,
                 sas_spurs_1999, lal_lakers_2000, lal_lakers_2001, lal_lakers_2002,
                 sas_spurs_2003, det_pistons_2004, sas_spurs_2005,
                 mia_heat_2006, sas_spurs_2007, bos_celtics_2008, lal_lakers_2009, lal_lakers_2010,
                 dal_mavs_2011, mia_heat_2012, mia_heat_2013, sas_spurs_2014, gsw_warriors_2015,
                 cle_cavs_2016, gsw_warriors_2017, gsw_warriors_2018,
                 tor_raptors_2019, lal_lakers_2020, mil_bucks_2021, gsw_warriors_2022,
                 ]

for df in champ_df_list:
  df = df.drop(columns=['CHAMP', 'PLAYER'], inplace=True)

#%%
## AGG GRID
# grid = AgGrid(df)

#%%
## VISUALIZATIONS ##

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

## BOX PLOTS ##

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

## BAR CHARTS ##
bar_usg_salary = px.bar(data_frame=champion_players,
                              x=champion_players['CHAMP'],
                              y=champion_players['SALARY'],
                              color=champion_players['USG%'],     # EXPERIENCE AGE MP APE
                              color_continuous_scale=Tropic,
                              color_discrete_sequence=Tropic,
                              # color_continuous_midpoint=10,
                              # color_discrete_map=team_logos_dict,
                              hover_name=champion_players['PLAYER'],
                              hover_data=champion_players[['CHAMP', 'SALARY', 'MP']], #'WS/$',
                              barmode='group',
                              title='USG% RELATIVE TO TEAM SALARY',
                              labels=chart_labels,
                              # template='simple_white+gridon',
                              # range_x=[1991,2023],
                              # range_y=[0,200000000],
                              height=750,
                            # category_orders={"InternetService": ["DSL", "Fiber optic", "No"],
#                               "gender": ["Female", "Male"]})
                              )

bar_WS_salary = px.bar(data_frame=champion_players,
                              x=champion_players['CHAMP'],
                              y=champion_players['SALARY'],
                              color=champion_players['WS'],     # EXPERIENCE AGE MP APE
                              color_continuous_scale=Tropic,
                              color_discrete_sequence=Tropic,
                              color_continuous_midpoint=10,
                              # color_discrete_map=team_logos_dict,
                              hover_name=champion_players['PLAYER'],
                              hover_data=champion_players[['CHAMP', 'SALARY', 'MP', 'WS']], #'WS/$',
                              barmode='group',
                              title='WIN SHARES (WS) METRIC RELATIVE TO CHAMPIONSHIP TEAM SALARY',
                              labels=chart_labels,
                              # template='simple_white+gridon',
                              # range_x=[1991,2023],
                              # range_y=[0,200000000],
                              height=750,
                              # width=1000,
                              )

bar_raptor_salary = px.bar(data_frame=champion_players,
                              x=champion_players['CHAMP'],
                              y=champion_players['SALARY'],
                              color=champion_players['RAPTOR'],     # EXPERIENCE AGE MP APE
                              color_continuous_scale=Tropic,
                              color_discrete_sequence=Tropic,
                              color_continuous_midpoint=0,
                              # color_discrete_map=team_logos_dict,
                              hover_name=champion_players['PLAYER'],
                              hover_data=champion_players[['CHAMP', 'SALARY', 'MP', 'RAPTOR']],
                              barmode='group',
                              title='RAPTOR METRIC RELATIVE TO CHAMPIONSHIP TEAM SALARY',
                              labels=chart_labels,
                              # template='simple_white+gridon',
                              # range_x=[1991,2022],
                              # range_y=[0,200000000],
                              height=750,
                              # width=1000,
                              )

bar_lebron_salary = px.bar(data_frame=lebron_val_players,
                              x=lebron_val_players['CHAMP'],
                              y=lebron_val_players['SALARY'],
                              color=lebron_val_players['LEBRON'],     # EXPERIENCE AGE MP APE
                              color_continuous_scale=Tropic,
                              color_discrete_sequence=Tropic,
                              # color_continuous_midpoint=10,
                              # color_discrete_map=team_logos_dict,
                              hover_name=lebron_val_players['PLAYER'],
                              hover_data=lebron_val_players[['CHAMP', 'SALARY', 'MP', 'LEBRON']],
                              barmode='group',
                              title='LEBRON METRIC RELATIVE TO CHAMPIONSHIP TEAM SALARY',
                              labels=chart_labels,
                              # template='simple_white+gridon',
                              # range_x=[1991,2022],
                              # range_y=[0,200000000],
                              height=750,
                              # width=1000,
                              )

bar_eWINS_WS = px.bar(data_frame=champion_players,
                              x=champion_players['CHAMP'],
                              y=champion_players['SALARY'],
                              color=champion_players['$MM/PlrWS'],     # EXPERIENCE AGE MP APE
                              color_continuous_scale=Tropic,
                              color_discrete_sequence=Tropic,
                              # color_continuous_midpoint=10,
                              # color_discrete_map=team_logos_dict,
                              hover_name=champion_players['PLAYER'],
                              hover_data=champion_players[['CHAMP', 'SALARY', 'MP']], #'WS/$',
                              barmode='group',
                              title='$MM / PLAYER WS RELATIVE TO TEAM SALARY',
                              labels=chart_labels,
                              # template='simple_white+gridon',
                              # range_x=[1991,2023],
                              # range_y=[0,200000000],
                              height=750,
                            # category_orders={"InternetService": ["DSL", "Fiber optic", "No"],
#                               "gender": ["Female", "Male"]})
                              )

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

## SCATTER MATRIX ##
scatter_matrix_metrics = px.scatter_matrix(champion_players,
                                         dimensions=['USG%', 'TS%', 'AST%/TO%', 'STOCK%', 'RAPTOR', 'LEBRON', 'WS', ],
                                         color=champion_players['WTD POS'],
                                         color_continuous_scale=Dense,
                                         color_discrete_sequence=Dense,
                                           # symbol=champion_players['TEAM'],
                                           # # symbol_sequence=team_logos_dict,
                                           # symbol_map=team_logos_dict,
                                         # color_discrete_map=team_logos_dict,
                                         hover_name=champion_players['PLAYER'],
                                         hover_data=champion_players[['MP', 'CHAMP']],
                                         title='PLAYER PERFORMANCE BY CHAMPIONSHIP TEAM',
                                         labels=chart_labels,
                                         # custom_data= [league_logo_list],
                                         height=800,
                                         # width=800,
                                         )

scatter_matrix_measurables = px.scatter_matrix(champion_players,
                                         dimensions=['BMI', 'APE', 'WS', 'RAPTOR', 'LEBRON'],
                                         color=champion_players['WTD POS'],
                                         color_continuous_scale=Dense,
                                         color_discrete_sequence=Dense,
                                         # color_discrete_map=team_logos_dict,
                                         hover_name=champion_players['PLAYER'],
                                         hover_data=champion_players[['MP', 'CHAMP']],
                                         title='PLAYER PERFORMANCE BY CHAMPIONSHIP TEAM',
                                         labels=chart_labels,
                                         # custom_data= [league_logo_list],
                                         height=800,
                                         # width=800,
                                         )

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

## SCATTER TERNARY ##

scatter_ternary_stl_blk_ast_to = px.scatter_ternary(data_frame=champion_players,
                                       a=champion_players['STL%'],
                                       b=champion_players['BLK%'],
                                       c=champion_players['AST%/TO%'],
                                       color=champion_players['WTD POS'],
                                        color_discrete_sequence=Dense,
                                       color_continuous_scale=Dense,
                                        color_continuous_midpoint=3,
                                       # symbol=champion_players['TEAM'], #'RD POS'
                                       #              symbol_map=team_logos_dict,
                                       size=champion_players['TS%'],
                                       size_max=20,
                                       opacity=.8,
                                       title='NBA CHAMPIONS -- STL% - BLK% - AST%/TO%',
                                       hover_name=champion_players['PLAYER'],
                                       hover_data=champion_players[['CHAMP', 'SALARY', 'MP',]],
                                       labels=chart_labels,
                                       height=900,
                                       )

scatter_ternary_ast_to_usg = px.scatter_ternary(data_frame=champion_players,
                                       a=champion_players['AST%'],
                                       b=champion_players['TO%'],
                                       c=champion_players['USG%'],
                                       color=champion_players['WTD POS'],
                                                color_discrete_sequence=Dense,
                                                color_continuous_scale=Dense,
                                                color_continuous_midpoint=3,
                                                symbol=champion_players['RD POS'],
                                                size=champion_players['TS%'],
                                                size_max=20,
                                       opacity=.8,
                                       title='NBA CHAMPIONS -- TS% - USG% - STOCK%',
                                       hover_name=champion_players['PLAYER'],
                                       hover_data=champion_players[['CHAMP', 'SALARY', 'MP', 'STL%', 'BLK%']],
                                       labels=chart_labels,
                                       height=900,
                                       )

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

## SCATTER 3D ##

scatter_3D_to_ast_usg = px.scatter_3d(data_frame=champion_players,
                                     x=champion_players['TO%'],
                                     y=champion_players['AST%'],
                                     z=champion_players['USG%'],
                                     color=champion_players['WTD POS'],
                                      symbol=champion_players['RD POS'],
                                     color_discrete_sequence=Dense,
                                     color_continuous_scale=Dense,
                                     color_continuous_midpoint=3,
                                     title='NBA CHAMPIONS -- TO% / AST% / USG% BY POSITION',
                                     hover_name=champion_players['PLAYER'],
                                     hover_data=champion_players[['CHAMP']], #'LOGO'
                                     # 'HEIGHT (IN)' 'WEIGHT (LBS)' 'BMI' 'W-SPAN (IN)'
                                     # custom_data=['LOGO'],
                                     # size=champion_players['WS'],
                                     # size_max=50,
                                     labels=chart_labels,
                                     # range_x=[0,360],
                                     # range_y=[-50,50],
                                     # range_z=[0,2500],
                                     # range_color=Sunsetdark,
                                     opacity=.8,
                                     height=1000,
                                     # width=1000,
                                     )

#%%

## HISTORICAL LINE CHARTS
box_eWINS_WS = px.bar(data_frame=champion_players,
                              x=champion_players['CHAMP'],
                              y=champion_players['$MM/eWIN'], #, '$MM/TmWIN']
                              color=champion_players['WTD POS'],     # EXPERIENCE AGE MP APE
                              color_discrete_sequence=Tropic,
                      color_continuous_scale=Dense,
                              # color_continuous_midpoint=10,
                              # color_discrete_map=team_logos_dict,
                              hover_name=champion_players['PLAYER'],
                              hover_data=champion_players[['CHAMP',]], #'WS/$',
                              title='$MM / PLAYER WS RELATIVE TO TEAM SALARY',
                              labels=chart_labels,
                              # template='simple_white+gridon',
                              # range_x=[1991,2023],
                              # range_y=[0,200000000],
                              height=750,
                            # category_orders={"InternetService": ["DSL", "Fiber optic", "No"],
#                               "gender": ["Female", "Male"]})
                              )

#%%

####################################################################################################################
## TRACE LINES ##

line_NBA_salary = go.Scatter(x=champion_players['CHAMP'], y=champion_players['NBA TM AVG SAL'],
                             line_color='#000000', mode='lines')

line_NBA_eWIN = go.Scatter(x=champion_players['CHAMP'], y=champion_players['$MM/eWIN'],
                             line_color='#000000', mode='lines')

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

## LOGO OVERLAY
# for x,y, png in zip(fig.data[0].x, fig.data[0].y, Path.cwd().joinpath("nfl-logos").glob("*.png")):
#     fig.add_layout_image(
#         x=x,
#         y=y,
#         source=Image.open(png),
#         xref="x",
#         yref="y",
#         sizex=2,
#         sizey=2,
#         xanchor="center",
#         yanchor="middle",
#     )

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

## DENSITY MAP
##

####################################################################################################################
#%%

#####################
### STREAMLIT APP ###
#####################

## CONFIGURATION ##
st.set_page_config(page_title='COMPOSITION OF NBA CHAMPIONS', layout='wide', initial_sidebar_state='auto') #, page_icon=":smirk:"

hide_menu_style = """
        <style>
        #MainMenu {visibility: hidden; }
        footer {visibility: hidden;}
        </style>
        """

st.markdown(hide_menu_style, unsafe_allow_html=True)

## CSS LAYOUT CUSTOMIZATION ##

th_props = [('font-size', '12px'),
            ('text-align', 'center'),
            ('font-weight', 'bold'),
            ('color', '#EBEDE9'), #6d6d6d #29609C
            ('background-color', '#29609C') #f7f7f9
            ]

td_props = [('font-size', '12px'),
            # ('text-align', 'center'),
            # ('font-weight', 'bold'),
            # ('color', '#EBEDE9'), #6d6d6d #29609C
            # ('background-color', '#29609C') #f7f7f9
            ]

df_styles = [dict(selector="th", props=th_props),
             dict(selector="td", props=td_props)]

col_format_dict = {
    # 'WTD POS': "{:.2}",
    #                'BMI': "{:.1}",
    #                'W-SPAN (IN)': "{:.1}",
    #                'APE': "{:.1}",
    #                'USG%': "{:.1}",
    #                'TS%': "{:.1}",
    #                'AST%/TO%': "{:.1}",
    #                'STOCK%': "{:.1}",
    #                # 'USG%': "{:.1}",
    #
    #                'WS': "{:,}",

#                    'O-WS': "{:,}",
#                    'D-WS': "{:,}",

#                    'TM_WS': "{:,}",
                   # #: "{:.1%}", #:"{:.1}x", "${:.2}", #"${:,}"
                   }

## SIDEBAR ##
# sidebar_header = st.sidebar.subheader('DIRECTORY:')

# sector_sidebar_select = st.sidebar.selectbox('SECTOR', (sector_list_of_names), help='SELECT CRE SECTOR')
# ticker_sidebar_select = st.sidebar.selectbox('TICKER', (sector_dict['apartment'])) #sector_sidebar_select

# sidebar_start = st.sidebar.date_input('START DATE', before)
# sidebar_end = st.sidebar.date_input('END DATE', today)
# if sidebar_start < sidebar_end:
#     st.sidebar.success('START DATE: `%s`\n\nEND DATE: `%s`' % (sidebar_start, sidebar_end))
# else:
#     st.sidebar.error('ERROR: END DATE BEFORE START DATE')

## HEADER ##
st.container()

st.title('CHAMPIONSHIP-CALIBER NBA ROSTER CONSTRUCTION')
st.write('*STATISTICAL BREAKDOWN OF HISTORICAL AND MODERN-DAY NBA CHAMPIONSHIP ROSTERS*')

## EAST LOGOS ##
EA_col_1, EA_col_2, EA_col_3, EA_col_4, EA_col_5, \
EC_col_1, EC_col_2, EC_col_3, EC_col_4, EC_col_5, \
ES_col_1, ES_col_2, ES_col_3, ES_col_4, ES_col_5 = st.columns(15)
EA_col_1.image(BKN_logo, caption='BKN', width=35)
EA_col_2.image(BOS_logo, caption='BOS', width=35)
EA_col_3.image(NYK_logo, caption='NYK', width=35)
EA_col_4.image(PHI_logo, caption='PHI', width=35)
EA_col_5.image(TOR_logo, caption='TOR', width=35)
EC_col_1.image(CHI_logo, caption='CHI', width=35)
EC_col_2.image(CLE_logo, caption='CLE', width=35)
EC_col_3.image(DET_logo, caption='DET', width=35)
EC_col_4.image(IND_logo, caption='IND', width=35)
EC_col_5.image(MIL_logo, caption='MIL', width=35)
ES_col_1.image(ATL_logo, caption='ATL', width=35)
ES_col_2.image(MIA_logo, caption='MIA', width=35)
ES_col_3.image(ORL_logo, caption='ORL', width=35)
ES_col_4.image(WAS_logo, caption='WAS', width=35)
ES_col_5.image(CHA_logo, caption='CHA', width=35)

## WEST LOGOS ##
WN_col_1, WN_col_2, WN_col_3, WN_col_4, WN_col_5, \
WP_col_1, WP_col_2, WP_col_3, WP_col_4, WP_col_5, \
WS_col_1, WS_col_2, WS_col_3, WS_col_4, WS_col_5 = st.columns(15)
WN_col_1.image(DEN_logo, caption='DEN', width=35)
WN_col_2.image(MIN_logo, caption='MIN', width=35)
WN_col_3.image(POR_logo, caption='POR', width=35)
WN_col_4.image(OKC_logo, caption='OKC', width=35)
WN_col_5.image(UTA_logo, caption='UTA', width=35)
WP_col_1.image(GSW_logo, caption='GSW', width=35)
WP_col_2.image(LAC_logo, caption='LAC', width=35)
WP_col_3.image(LAL_logo, caption='LAL', width=35)
WP_col_4.image(PHX_logo, caption='PHX', width=35)
WP_col_5.image(SAC_logo, caption='SAC', width=35)
WS_col_1.image(NOP_logo, caption='NOP', width=35)
WS_col_2.image(DAL_logo, caption='DAL', width=35)
WS_col_3.image(HOU_logo, caption='HOU', width=35)
WS_col_4.image(SAS_logo, caption='SAS', width=35)
WS_col_5.image(MEM_logo, caption='MEM', width=35)

tab_0, tab_1, tab_2, tab_3, tab_4, tab_5, tab_6, tab_7, tab_8, tab_9, tab_10, \
tab_11, tab_12, tab_13, tab_14, tab_15, tab_16, tab_17, tab_18, tab_19, tab_20, \
tab_21, tab_22, tab_23, tab_24, tab_25, tab_26, tab_27, tab_28, tab_29, tab_30, tab_31, tab_32, \
    = st.tabs(['NBA',
               '2022-GSW', '2021-MIL', '2020-LAL', '2019-TOR', '2018-GSW',
               '2017-GSW', '2016-CLE', '2015-GSW', '2014-SAS', '2013-MIA',
               '2012-MIA', '2011-DAL', '2010-LAL', '2009-LAL', '2008-BOS',
               '2007-SAS', '2006-MIA', '2005-SAS', '2004-DET', '2003-SAS',
               '2002-LAL', '2001-LAL', '2000-LAL', '1999-SAS', '1998-CHI',
               '1997-CHI', '1996-CHI', '1995-HOU', '1994-HOU', '1993-CHI',
               '1992-CHI', '1991-CHI'
               ])

# 'ATL', 'BKN', 'BOS', 'CHA', 'CHI', 'CLE', 'DET', 'IND', 'MIA', 'MIL', 'NYK', 'ORL', 'PHI', 'TOR', 'WAS',
#                'DAL', 'DEN', 'HOU', 'GSW', 'LAC', 'LAL', 'MEM', 'MIN', 'NOP', 'OKC', 'PHX', 'POR', 'SAC', 'SAS', 'UTA',

with tab_0:
    # st.subheader('ALL SECTORS')
    st.plotly_chart(scatter_matrix_metrics, use_container_width=True, sharing="streamlit")

    ## BAR - WS SALARY ##
    st.plotly_chart(bar_WS_salary.add_traces(line_NBA_salary).add_layout_image(court_img_dict), use_container_width=True, sharing="streamlit")

    st.image(capstone_court, width=1000, use_column_width=True)

    ## SCATTER TERNARY ##

    # left, right = st.columns(2)
    # with left:
    #     st.plotly_chart(scatter_ternary_ast_to_usg, use_container_width=True, sharing="streamlit") #.add_layout_image(court_img_dict)
    # with right:
    #     st.plotly_chart(scatter_ternary_stl_blk_ast_to, use_container_width=True, sharing="streamlit") #.add_layout_image(court_img_dict)

    ## SCATTER MATRIX ##
    # st.plotly_chart(scatter_matrix_teams, use_container_width=True, sharing="streamlit")

    # st.plotly_chart(scatter_matrix_measurables, use_container_width=True, sharing="streamlit")

    # st.plotly_chart(box_eWINS_WS.add_traces(line_NBA_eWIN).add_layout_image(court_img_dict), use_container_width=True, sharing="streamlit")

    ## 3D SCATTER ##
    # st.plotly_chart(scatter_3D_to_ast_usg.add_layout_image(court_img_dict_3D), use_container_width=True, sharing="streamlit")

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250) # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300) # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250) # caption='EASTERN CONFERENCE'

    ## FORM FUNCTIONS ##
    # @st.cache(persist=True, allow_output_mutation=True, suppress_st_warning=True)

    ## DISCOVERY INFORMATION ##
    # st.plotly_chart(disc_info_1.update_yaxes(categoryorder='total ascending'), use_container_width=True, sharing="streamlit")

    ## EXTERNAL LINKS ##

    github_link = '[GITHUB REPOSITORY](https://github.com/nehat312/NBA-championship-caliber/)'
    nba_site_link = '[NBA.com](https://www.nba.com/)'
    bbref_site_link = '[BASKETBALL REFERENCE](https://www.basketball-reference.com/)'

    link_col_1, link_col_2, link_col_3 = st.columns(3)
    ext_link_1 = link_col_1.markdown(github_link, unsafe_allow_html=True)
    ext_link_2 = link_col_2.markdown(nba_site_link, unsafe_allow_html=True)
    ext_link_3 = link_col_3.markdown(bbref_site_link, unsafe_allow_html=True)

with tab_1:
    st.subheader('2021-2022 GOLDEN STATE WARRIORS')
    st.image(GSW_logo)
    st.dataframe(gsw_warriors_2022.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_2:
    st.subheader('2020-2021 MILWAUKEE BUCKS')
    st.image(MIL_logo)
    st.dataframe(mil_bucks_2021.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_3:
    st.subheader('2019-2020 LOS ANGELES LAKERS')
    st.image(LAL_logo)
    st.dataframe(lal_lakers_2020.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_4:
    st.subheader('2018-2019 TORONTO RAPTORS')
    st.image(TOR_logo)
    st.dataframe(tor_raptors_2019.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_5:
    st.subheader('2017-2018 GOLDEN STATE WARRIORS')
    st.image(GSW_logo)
    st.dataframe(gsw_warriors_2018.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_6:
    st.subheader('2016-2017 GOLDEN STATE WARRIORS')
    st.image(GSW_logo)
    st.dataframe(gsw_warriors_2017.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_7:
    st.subheader('2015-2016 CLEVELAND CAVALIERS')
    st.image(CLE_logo)
    st.dataframe(cle_cavs_2016.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_8:
    st.subheader('2014-2015 GOLDEN STATE WARRIORS')
    st.image(GSW_logo)
    st.dataframe(gsw_warriors_2015.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_9:
    st.subheader('2013-2014 SAN ANTONIO SPURS')
    st.image(SAS_logo)
    st.dataframe(sas_spurs_2014.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_10:
    st.subheader('2012-2013 MIAMI HEAT')
    st.image(MIA_logo)
    st.dataframe(mia_heat_2013.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_11:
    st.subheader('2011-2012 MIAMI HEAT')
    st.image(MIA_logo)
    st.dataframe(mia_heat_2012.style.format(col_format_dict).set_table_styles(df_styles))
    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_12:
    st.subheader('2010-2011 DALLAS MAVERICKS')
    st.image(DAL_logo)
    st.dataframe(dal_mavs_2011.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_13:
    st.subheader('2009-2010 LOS ANGELES LAKERS')
    st.image(LAL_logo)
    st.dataframe(lal_lakers_2010.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_14:
    st.subheader('2008-2009 LOS ANGELES LAKERS')
    st.image(LAL_logo)
    st.dataframe(lal_lakers_2009.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_15:
    st.subheader('2007-2008 BOSTON CELTICS')
    st.image(BOS_logo)
    st.dataframe(bos_celtics_2008.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_16:
    st.subheader('2006-2007 SAN ANTONIO SPURS')
    st.image(SAS_logo)
    st.dataframe(sas_spurs_2007.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_17:
    st.subheader('2005-2006 MIAMI HEAT')
    st.image(MIA_logo)
    st.dataframe(mia_heat_2006.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_18:
    st.subheader('2004-2005 SAN ANTONIO SPURS')
    st.image(SAS_logo)
    st.dataframe(sas_spurs_2005.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_19:
    st.subheader('2003-2004 DETROIT PISTONS')
    st.image(DET_logo)
    st.dataframe(det_pistons_2004.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_20:
    st.subheader('2002-2003 SAN ANTONIO SPURS')
    st.image(SAS_logo)
    st.dataframe(sas_spurs_2003.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_21:
    st.subheader('2001-2002 LOS ANGELES LAKERS')
    st.image(LAL_logo)
    st.dataframe(lal_lakers_2002.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_22:
    st.subheader('2000-2001 LOS ANGELES LAKERS')
    st.image(LAL_logo)
    st.dataframe(lal_lakers_2001.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_23:
    st.subheader('1999-2000 LOS ANGELES LAKERS')
    st.image(LAL_logo)
    st.dataframe(lal_lakers_2000.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_24:
    st.subheader('1998-1999 SAN ANTONIO SPURS')
    st.image(SAS_logo)
    st.dataframe(sas_spurs_1999.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_25:
    st.subheader('1997-1998 CHICAGO BULLS')
    st.image(CHI_logo)
    st.dataframe(chi_bulls_1998.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_26:
    st.subheader('1996-1997 CHICAGO BULLS')
    st.image(CHI_logo)
    st.dataframe(chi_bulls_1997.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_27:
    st.subheader('1995-1996 CHICAGO BULLS')
    st.image(CHI_logo)
    st.dataframe(chi_bulls_1996.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_28:
    st.subheader('1994-1995 HOUSTON ROCKETS')
    st.image(HOU_logo)
    st.dataframe(hou_rockets_1995.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_29:
    st.subheader('1993-1994 HOUSTON ROCKETS')
    st.image(HOU_logo)
    st.dataframe(hou_rockets_1994.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_30:
    st.subheader('1992-1993 CHICAGO BULLS')
    st.image(CHI_logo)
    st.dataframe(chi_bulls_1993.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_31:
    st.subheader('1991-1992 CHICAGO BULLS')
    st.image(CHI_logo)
    st.dataframe(chi_bulls_1992.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

with tab_32:
    st.subheader('1990-1991 CHICAGO BULLS')
    st.image(CHI_logo)
    st.dataframe(chi_bulls_1991.style.format(col_format_dict).set_table_styles(df_styles))

    ## LEAGUE LOGOS ##
    east_col_1, nba_col_2, west_col_3 = st.columns(3)
    east_col_1.image(East_logo, width=250)  # caption='WESTERN CONFERENCE'
    nba_col_2.image(nba_logo_1, width=300)  # caption='NATIONAL BASKETBALL ASSOCIATION'
    west_col_3.image(West_logo, width=250)  # caption='EASTERN CONFERENCE'

## SCRIPT TERMINATION ##
st.stop()

### INTERPRETATION ###

### SCRATCH NOTES ###

# top-level filters
# job_filter = st.selectbox (“Select the status”, pd.unique (df(“job”)))
# df = df [df [“status”] == status_filter]

## METRICS - TOP of each team?
# kpix.metric
# {
# label = “Fitness”,
# value = f”$ { round ( balance, 4) }”,
# delta = - round (balance / count_fitness) * 100,
# }

## PAGE BACKGROUND ##

# def add_bg_from_url():
#     st.markdown(
#          f"""
#          <style>
#          .stApp {{
#              background-image: url("images/Court1.png");
#              background-attachment: fixed;
#              background-size: cover
#          }}
#          </style>
#          """,
#          unsafe_allow_html=True
#      )
#
# add_bg_from_url()

# CONFIG TEMPLATE
    # st.set_page_config(page_title="CSS hacks", page_icon=":smirk:")
    #
    # c1 = st.container()
    # st.markdown("---")
    # c2 = st.container()
    # with c1:
    #     st.markdown("Hello")
    #     st.slider("World", 0, 10, key="1")
    # with c2:
    #     st.markdown("Hello")
    #     st.slider("World", 0, 10, key="2")

# STYLE WITH CSS THROUGH MARKDOWN
    # st.markdown("""
    # <style>
    # div[data-testid="stBlock"] {
    #     padding: 1em 0;
    #     border: thick double #32a1ce;
    # }
    # </style>
    # """, unsafe_allow_html=True)

# STYLE WITH JS THROUGH HTML IFRAME
    # components.html("""
    # <script>
    # const elements = window.parent.document.querySelectorAll('div[data-testid="stBlock"]')
    # console.log(elements)
    # elements[0].style.backgroundColor = 'paleturquoise'
    # elements[1].style.backgroundColor = 'lightgreen'
    # </script>
    # """, height=0, width=0)

# st.markdown("""
#             <style>
#             div[data-testid="stBlock"] {padding: 1em 0; border: thick double #32a1ce; color: blue}
#             </style>
#             """,
#             unsafe_allow_html=True)

# style={'textAlign': 'Center', 'backgroundColor': 'rgb(223,187,133)',
#                                            'color': 'black', 'fontWeight': 'bold', 'fontSize': '24px',
#                                            'border': '4px solid black', 'font-family': 'Arial'}),

#pattern_shape = "nation", pattern_shape_sequence = [".", "x", "+"]

            # fig = px.bar(df, x="sex", y="total_bill", color="smoker", barmode="group", facet_row="time", facet_col="day",
            #        category_orders={"day": ["Thur", "Fri", "Sat", "Sun"], "time": ["Lunch", "Dinner"]})

            # fig = px.scatter_matrix(df, dimensions=["sepal_width", "sepal_length", "petal_width", "petal_length"], color="species")

            # fig = px.parallel_categories(df, color="size", color_continuous_scale=px.colors.sequential.Inferno)

            # fig = px.parallel_coordinates(df, color="species_id", labels={"species_id": "Species",
            #                   "sepal_width": "Sepal Width", "sepal_length": "Sepal Length",
            #                   "petal_width": "Petal Width", "petal_length": "Petal Length", },
            #                     color_continuous_scale=px.colors.diverging.Tealrose, color_continuous_midpoint=2)

# from IPython.display import HTML
# import base64
# # convert your links to html tags
# def path_to_image_html(path):
#     return '<img src="'+ path + '" width="60" >'
# HTML(champion_players[['LOGO']].to_html(escape=False, formatters=dict(image=path_to_image_html)))


import pytorch_lightning as pl
from pytorch_lightning.utilities.types import EVAL_DATALOADERS, STEP_OUTPUT, TRAIN_DATALOADERS

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data.dataloader import DataLoader

from einops import rearrange, repeat
from rotary_embedding_torch import RotaryEmbedding

from datasets import load_dataset

from typing import Any, Tuple, Optional

from itertools import chain

import argparse

from tokenizers import Tokenizer, models, decoders, pre_tokenizers, trainers

class MSR(nn.Module):
    def __init__(self,
                 hidden_dim: int,
                 head_dim: int,
                 ):
        super().__init__()

        self.n_heads = n_heads = hidden_dim // head_dim
        self.head_dim = head_dim

        self.gn = nn.GroupNorm(n_heads, n_heads)
        self.act = nn.Mish()

        self.register_buffer('gamma', 1 - torch.pow(2.0, -5.0 - torch.arange(0, n_heads)))

        self.wg = nn.Linear(hidden_dim, hidden_dim, bias=False)
        self.wo = nn.Linear(hidden_dim, hidden_dim, bias=False)

        self.wqkv = nn.Linear(hidden_dim, 3 * hidden_dim, bias=False)
        self.pos_emb = RotaryEmbedding(head_dim // 2, use_xpos=True)

    def forward(self, x: torch.Tensor, hidden_state: Optional[torch.Tensor] = None) -> Tuple[torch.Tensor, Optional[torch.Tensor]]:
        """
            x = input vector of shape [bs, seqlen, hidden dim]
            hidden_state = recurrent state from previous step. Initialized by layer itself is null and module is in eval state
        """
        bs, seqlen, _ = x.shape

        qkv: torch.Tensor = self.wqkv(x) # [bs, seqlen, 3xhidden dim]
        qkv = rearrange(qkv, 'B S (H D) -> B H S D', H=self.n_heads)
        q, k, v = qkv.chunk(3, dim=-1) # 3x[bs, heads, seqlen, head dim]

        # Eq. (5)
        # Apply xPos embedding on Q/K
        q, k = self.pos_emb.rotate_queries_and_keys(q, k)

        if self.training:
            # Eq. (5)
            # Dnm = pow(gamma, n-m) if n>=m else 0
            # TODO: implement Retention Score normalization
            nm_index = torch.arange(1, seqlen+1, device=x.device)
            nm = repeat(nm_index, 'W -> W H', H=seqlen) - repeat(nm_index, 'W -> H W', H=seqlen)
            decay_mask = torch.pow(self.gamma.view(-1, 1, 1), nm) * (nm >= 0).int()

            ret: torch.Tensor = q @ k.transpose(-1, -2)
            ret = ret * decay_mask
            ret = ret @ v
            ret = self.gn(ret)
        else:
            # Eq. (6)
            if hidden_state is None:
                hidden_state = torch.zeros(bs, self.n_heads, q.shape[-1], v.shape[-1])

            hidden_state = self.gamma.view(1, -1, 1, 1) * hidden_state + k.transpose(-1, -2) @ v
            ret = q @ hidden_state

        # Eq. (8)
        y = rearrange(ret, 'B H S D -> B S (H D)')
        y = self.act(self.wg(x)) * y
        y = self.wo(y)

        return y, hidden_state

class FFN(nn.Module):
    def __init__(self, hidden_dim: int,):
        super().__init__()
        self.w1 = nn.Linear(hidden_dim, hidden_dim)
        self.w2 = nn.Linear(hidden_dim, hidden_dim)
        self.act = nn.GELU()

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return self.w2(self.act(self.w1(x)))

class RetNetBlock(nn.Module):
    def __init__(self, hidden_dim: int,
                 head_dim: int,):
        super().__init__()

        self.ln1 = nn.LayerNorm(hidden_dim)
        self.msr = MSR(hidden_dim=hidden_dim, head_dim=head_dim)
        self.ln2 = nn.LayerNorm(hidden_dim)
        self.ffn = FFN(hidden_dim)

    def forward(self, x: torch.Tensor, hidden_state: Optional[torch.Tensor] = None) -> Tuple[torch.Tensor, torch.Tensor]:
        # Eq. (9)
        y, hidden_state = self.msr(self.ln1(x), hidden_state)
        y = y + x
        return self.ffn(self.ln2(y)) + y, hidden_state

class RetentionNetwork(nn.Module):
    def __init__(self,
                 vocab_size: int,
                 hidden_dim: int,
                 n_layers: int,
                 head_dim: int = 256,
                 ):
        super().__init__()
        self.emb = nn.Embedding(vocab_size, hidden_dim)
        self.layers = nn.ModuleList([RetNetBlock(hidden_dim=hidden_dim, head_dim=head_dim) for i in range(n_layers)])

    def forward(self, x: torch.LongTensor) -> torch.Tensor:
        x = self.emb(x)
        hidden_state: torch.Tensor = None

        for layer in self.layers:
            x, hidden_state = layer(x, hidden_state)

        return x

class RetNetClassification(pl.LightningModule):
    def __init__(self,
                 vocab_size: int,
                 hidden_dim: int,
                 n_layers: int,
                 head_dim: int = 256,
                 max_seqlen: int = 512,
                 num_classes: int = 2,
                 *,
                 lr = 0.001,
                 betas = (0.9, 0.98),
                 weight_decay = 0.05
                 ):
        super().__init__()

        self.hidden_dim = hidden_dim
        self.max_seqlen = max_seqlen

        self.retnet = RetentionNetwork(vocab_size=vocab_size, hidden_dim=hidden_dim, n_layers=n_layers, head_dim=head_dim)
        self.head = nn.Linear(max_seqlen * hidden_dim, num_classes)

        self.lr = lr
        self.betas = betas
        self.weight_decay = weight_decay

        self.loss = nn.CrossEntropyLoss()

    def forward(self, x: torch.LongTensor) -> torch.Tensor:
        y = self.retnet(x)
        y = self.head(y.view(-1, self.max_seqlen * self.hidden_dim))
        y = F.softmax(y, dim=1)
        return y

    def configure_optimizers(self):
        optim = torch.optim.AdamW(chain(self.retnet.parameters(), self.head.parameters()),
                                  lr=self.lr,
                                  betas=self.betas,
                                  weight_decay=self.weight_decay
                                  )
        return optim

    def training_step(self, batch, batch_idx):
        x, labels = batch
        y = self.forward(x)

        loss = self.loss(y, labels)
        self.log_dict({'train_loss' : loss})

        return loss

    def test_step(self, batch, batch_idx):
        x, labels = batch
        y = self.forward(x)

        loss = self.loss(y, labels)

        self.log_dict({'test_loss' : loss})

class IMDBDataModule(pl.LightningDataModule):
    def __init__(self,
                 tokenizer: Tokenizer,
                 train_batch_size: int = 32,
                 test_batch_size: int = 4,
                 predict_batch_size: int = 4,
                 max_len: int = 512,
                 ):
        super().__init__()
        self.name = 'imdb'
        self.train_batch_size = train_batch_size
        self.test_batch_size = test_batch_size
        self.predict_batch_size = predict_batch_size
        self.max_len = 512

        self.tokenizer = tokenizer

    def prepare_data(self):
        load_dataset(self.name)

    def train_tokenizer(self, trainer: trainers.Trainer):
        for split, dataset in load_dataset(self.name).items():
            def batch_iterator(batch_size=1000):
                for i in range(0, len(dataset), batch_size):
                    yield dataset[i:i+batch_size]["text"]

            print(f'Train tokenizer for split {split}')

            self.tokenizer.train_from_iterator(batch_iterator(), trainer, length=len(dataset))

    def tokenize(self, item):
        return {
                'tokens' : [o.ids for o in self.tokenizer.encode_batch(item['text'])]
                }

    def setup(self, stage: str):
        if stage == 'fit':
            self.train_dataset = load_dataset(self.name, split='train')
            self.train_dataset.set_format(type='torch')
            self.train_dataset = self.train_dataset.map(lambda e: self.tokenize(e), batched=True)

        elif stage == 'test':
            self.test_dataset = load_dataset(self.name, split='test')
            self.test_dataset.set_format(type='torch')
            self.test_dataset = self.test_dataset.map(lambda e: self.tokenize(e), batched=True)

        elif stage == 'predict':
            self.predict_dataset = load_dataset(self.name, split='unsupervised')
            self.predict_dataset.set_format(type='torch')
            self.predict_dataset = self.predict_dataset.map(lambda e: self.tokenize(e), batched=True)

    def collate(self, batch):
        bs = len(batch)
        batched_ids = torch.zeros(bs, self.max_len, dtype=torch.long)
        batched_labels = torch.zeros(bs, dtype=torch.long)

        for id, item in enumerate(batch):
            tokens, labels = item['tokens'], item['label']
            l = min(tokens.shape[0], self.max_len)
            batched_ids[id, :l] = tokens[:l]
            batched_labels[id] = labels
        return batched_ids, batched_labels

    def train_dataloader(self):
        return DataLoader(self.train_dataset, batch_size=self.train_batch_size, collate_fn=lambda e: self.collate(e))

    def test_dataloader(self):
        return DataLoader(self.test_dataloader, batch_size=self.test_batch_size, collate_fn=lambda e: self.collate(e))

    def predict_dataloader(self):
        return DataLoader(self.predict_dataset, batch_sampler=self.predict_batch_size, collate_fn=lambda e: self.collate(e))

if __name__=='__main__':

    torch.set_float32_matmul_precision('high')

    try:
        tokenizer = Tokenizer.from_file('imdb.json')
        tokenizer_trainer = None
    except:
        tokenizer = Tokenizer(models.WordPiece(unk_token="[UNK]"))

        tokenizer.decoder = decoders.WordPiece()
        tokenizer.pre_tokenizer = pre_tokenizers.Whitespace()
        tokenizer_trainer = trainers.WordPieceTrainer(vocab_size=3000,
                                                      special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"]
                                                      )

    datamodule = IMDBDataModule(tokenizer=tokenizer)
    datamodule.prepare_data()

    if tokenizer_trainer is not None:
        datamodule.train_tokenizer(tokenizer_trainer)
        tokenizer.save('imdb.json')

    model = RetNetClassification(vocab_size=tokenizer.get_vocab_size(), hidden_dim=256, n_layers=3, head_dim=32, max_seqlen=512)
    # model = MSR(256, 32)
    # model = model.eval()
    # x = torch.zeros(1, 512, dtype=torch.long)
    # y = model(x)
    # print(x.shape, y.shape)

    trainer = pl.Trainer(max_epochs=10)

    trainer.fit(model, datamodule)


import random, time

# 몬스터의 기본정보
class Monster:
    def __init__(self, name, hp, damage):
        self.name = name
        self.hp = hp
        self.damage = damage
        self.ex = 1

    def attack(self, other):
        time.sleep(0.5)
        damage = random.randint(int(self.damage * 0.8), int(self.damage * 1.2))
        other.hp = max(other.hp - damage, 0)
        self.attack_name = random.choice(
            ["세미콜론 지우기!", "Error 공격!", "오타 공격!", "이게 왜 돼? 왜 안 돼? | 부조리공격!"]
        )
        print(
            f"\n{self.name}의 {self.attack_name}\n\n\t{damage}만큼의 공격을 받아 HP가 {other.hp} 되었습니다."
        )

    def status_check(self):
        print(f"{self.name}의 HP : {self.hp} 공격력 : {self.damage}")

# # 몬스터 HTML
# class HTML_Monster(Monster):
#     def __init__(self, other):
#         super().__init__()
#         other
#     # 부모 클래스에 존재하는 status_check 메소드를 overriding 합니다.
#     def status_check(self):
#         print(f"HTML의 HP : {self.hp}")

# # 몬스터 CSS
# class CSS_Monster(Monster):
#     def __init__(self, other):
#         super().__init__()

#     def status_check(self):
#         print(f"CSS의 HP : {self.hp}")

# # 몬스터 JS
# class JS_Monster(Monster):
#     def __init__(self, other):
#         super().__init__()

#     def status_check(self):
#         print(f"JS의 HP : {self.hp}")

# # 몬스터 Python
# class Python_Monster(Monster):
#     def __init__(self, other):
#         super().__init__()

#     def status_check(self):
#         print(f"Python의 HP : {self.hp}")

# # 몬스터 알고리즘
# class Algorithm_Monster(Monster):
#     def __init__(self, other):
#         super().__init__()

#     def status_check(self):
#         print(f"Algorithm의 HP : {self.hp}")


from flask import Flask, jsonify, request
from flask_cors import CORS
import pymongo
import requests

app = Flask(__name__)
app.config.from_object(__name__)

# enable CORS
CORS(app, resources={r'/*': {'origins': '*'}})

# TO-DO - change from hard coded to get values from env variables
MONGO_HOST = 'localhost'
MONGO_USER = 'root'
MONGO_PASS = '1234'
MONGO_PORT = '27018'
MONGO_DB = 'admin'

USER_COLLECTION = 'users'
SDK_COLLECTION = 'sdk'

VAST_EP = 'https://6u3td6zfza.execute-api.us-east-2.amazonaws.com/prod/ad/vast'

mongo_client = pymongo.MongoClient('mongodb://' +
                                   MONGO_USER +
                                   ':' + MONGO_PASS +
                                   '@' + MONGO_HOST +
                                   ':' + MONGO_PORT + '/')
db = mongo_client[MONGO_DB]

@app.route('/')
def hello():
    res = {}
    return jsonify(res)

@app.route('/GetAd', methods=['GET'])
def get_ad():
    # Get Params from the request
    # The rest variables from the assignment will not be in use (session_id, platform, country)
    data = request.get_json()
    sdk_version = request.args.get('sdk_version')
    user_name = request.args.get('user_name')

    # If both params exist in request increment the action amount
    if sdk_version is not None and user_name is not None:
        user_cnt(user_name,'requests')
        sdk_cnt(sdk_version, 'requests')

    # Return Vast ad response
    return get_vast()

@app.route('/Impression')
def set_impression():
    # Get Params from the request
    # The rest variables from the assignment will not be in use (session_id, platform, country)
    data = request.get_json()
    sdk_version = request.args.get('sdk_version')
    user_name = request.args.get('user_name')

    # If both params exist in request increment the action amount
    if sdk_version is not None and user_name is not None:
        user_cnt(user_name,'impressions')
        sdk_cnt(sdk_version, 'impressions')

    return ('', 204)

@app.route('/GetStats')
def get_stats():
    # Get Params from the request
    filter_type = request.args.get('filter_type')

    # Run rate calculation quesry on DB
    result = get_calculated_rate(filter_type)
    if result is not None:
        return jsonify(result)

    return jsonify({})

def user_cnt(id,action):
    try:
        collection = db[USER_COLLECTION]
        collection.update({'user_id': id},
                          {'$inc': {'impressions': 1 if action == 'impressions' else 0,
                                    'requests': 1 if action == 'requests' else 0}},
                          upsert=True)
    except:
        print("Error occured while updating DB")

def sdk_cnt(id, action):
    try:
        collection = db[SDK_COLLECTION]
        collection.update({'sdk': id},
                          {'$inc': {'impressions': 1 if action == 'impressions' else 0,
                                    'requests': 1 if action == 'requests' else 0}},
                          upsert=True)
    except:
        print("Error occured while updating DB")

def get_vast():
    try:
        response = requests.get(VAST_EP)
        if response.status_code == 200:
            body = response.content
            return body.decode('utf-8')
    except:
        print("Error occured while requesting vast")
        return None

def get_calculated_rate(type):
    try:
        collection = db[type]
        result = collection.aggregate(get_rate_query())
        return list(result)
    except:
        print("Error occured while running calculation")
        return None

def get_rate_query():
    return [{
            '$addFields': {
                'rate': {
                    # handle zero derived case & calculate rate
                    '$cond': [{ '$eq': ["$impressions", 0]}, 0, {"$divide": ['$requests', '$impressions']}]
                },
                # Remove irrelevant fields
                'impressions' : '$$REMOVE',
                'requests' : '$$REMOVE',
                '_id' : '$$REMOVE'
            }
        }]

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=5000)


import os
import glob
import numpy as np
import matplotlib
matplotlib.rcParams['pdf.fonttype'] = 42
matplotlib.rcParams['ps.fonttype'] = 42
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sn
from scipy import signal

import define
from data_processing import raw_waveform_processing, brf_extraction, ACam

# all plotting graphs
class plots():
    #show plot
    def show_plot(waveform):
        plt.plot(waveform)
        plt.show()

    #save plot
    def save_plot(waveform, plot_name):
        plt.plot(waveform)
        plt.title(plot_name)
        plt.savefig(plot_name + '.png')
        plt.clf()

    '''
    plotting three different waveforms for Figure 1 in BuildSys paper
    '''
    def plot_three_waveforms(csv_brf_path, save_path, title_name):
        cwd = os.getcwd()
        os.chdir(csv_brf_path)
        csv_names = glob.glob('*.csv')
        colors = list(['r', 'g', 'b'])
        temp_labels = list(['Incandescent', 'CFL', 'LED'])

        # font_size = 18
        plt.rcParams["font.family"] = "Times New Roman"
        font_size = 11

        # fig, axs = plt.subplots(len(csv_names), constrained_layout=True, figsize = (8,15))
        for i in range(len(csv_names)):
            processed = raw_waveform_processing(csv_names[i])
            time = processed.time
            brf = processed.brf
            # time, brf = raw_waveform_processing.clean_brf(time, brf)
            brf = raw_waveform_processing.normalize(brf)
            smoothed = raw_waveform_processing.moving_average(raw_waveform_processing.savgol(brf, define.savgol_window), define.mov_avg_w_size)
            smoothed_time = raw_waveform_processing.moving_average(time, define.mov_avg_w_size)
            # plt.plot(time, brf, colors[i])
            plt.plot(time, brf, colors[i], linewidth = 3, alpha = 1 - 0.25*i)
            # plt.plot(smoothed_time, smoothed, colors[i], linewidth = 3)
            # plt.plot(smoothed_time, smoothed, colors[i], linewidth = 3, markersize = 1, label = temp_labels[i])
            # plt.plot(normalized_smoothed, colors[i])
            plt.xlabel('Time (s)', fontsize = font_size)
            plt.ylabel('Normalized Intensity', fontsize = font_size)
            plt.xticks(fontsize = font_size)
            plt.yticks(fontsize = font_size)
            plt.locator_params(axis='x', nbins=5)
            # plt.tight_layout()
            plt.gcf().subplots_adjust(bottom=0.15)
            # axs[i].plot(time, brf)
            # axs[i].set_xlabel('Time (s)', fontsize = 18)
            # axs[i].set_ylabel('Normalized Intensity', fontsize = 18)

        # plt.title(title_name, fontsize = 18)
        plt.legend(loc = 'upper left', fontsize = font_size, prop={'size': 9})
        plt.tight_layout()
        plt.show()
        # plt.savefig(save_path + '\\' + title_name + '.png')
        # plt.clf()

        os.chdir(cwd)

    #confusion matrix for bulb types only
    def confusion_matrix_type(ground_list, predicted_list, bulb_types, title):
        bulb_types_list = list(bulb_types[:4])
        bulb_types = list(bulb_types)
        prediction_matrix = np.zeros((len(bulb_types_list),len(bulb_types_list)))
        total = np.zeros((len(bulb_types_list),len(bulb_types_list)))

        assert len(ground_list) == len(predicted_list)

        for i in range(len(ground_list)):
            ground_index = bulb_types.index(ground_list[i])
            predicted_index = bulb_types.index(predicted_list[i])
            if ground_index < 4 and predicted_index < 4: #excluding halogen-xenon and halogen-incandescent
                prediction_matrix[ground_index][predicted_index] += 1
                total[ground_index][:] += 1

        confusion_matrix = np.divide(prediction_matrix, total)

        df_cm = pd.DataFrame(confusion_matrix, index = [i for i in bulb_types_list], columns = [i for i in bulb_types_list])
        #(12,7) if just figure title
        plt.figure(figsize = (13,9))
        sn.heatmap(df_cm, annot=True)
        plt.title(title)
        plt.xlabel('Predicted', fontsize = 16)
        plt.ylabel('Expected', fontsize = 16)
        plt.yticks(va = 'center')
        plt.show()

    #issues with the ticks for a confusion matrix of the entire BRF database
    #show the confusion matrix for unique BRFs
    def confusion_matrix_unique(ground_list, predicted_list, unique_brf_names, title):
        prediction_matrix = np.zeros((len(unique_brf_names),len(unique_brf_names)))
        total_matrix = np.zeros((len(unique_brf_names),len(unique_brf_names)))

        assert len(ground_list) == len(predicted_list)

        for i in range(len(ground_list)):
            ground_index = unique_brf_names.index(ground_list[i])
            predicted_index = unique_brf_names.index(predicted_list[i])
            prediction_matrix[ground_index][predicted_index] += 1
            total_matrix[ground_index][:] += 1

        confusion_matrix = np.divide(prediction_matrix, total_matrix)

        df_cm = pd.DataFrame(confusion_matrix, index = [i for i in unique_brf_names], columns = [i for i in unique_brf_names])
        plt.figure(figsize = (8,7)).tight_layout()
        sn.heatmap(df_cm)
        plt.title(title)
        plt.xlabel('Predicted', fontsize = 16)
        #font size is too small, and not sure if can make it smaller
        plt.xticks(np.arange(0.5, len(unique_brf_names), 1), unique_brf_names, rotation = 45, ha = 'right', fontsize = 6)
        plt.ylabel('Expected', fontsize = 16)
        plt.yticks(np.arange(0.5, len(unique_brf_names), 1), unique_brf_names, rotation = 45, va = 'top', fontsize = 6)
        plt.tight_layout()
        plt.show()

    '''
    not using this anymore
    '''
    def misclass_bar_graph(name_list, misclassification_array, plot_title):
        # plt.figure(figsize = (15,8))
        plt.figure(figsize = (15,5))
        plt.bar(name_list, misclassification_array)
        plt.xticks(rotation = 45, ha = 'right', fontsize = 8)
        plt.tight_layout()
        plt.title(plot_title)
        plt.show()

    def k_and_k_fold(k_list, overall_accuracy, cfl_accuracy, halogen_accuracy, incandescent_accuracy, led_accuracy, title):
        plt.plot(overall_accuracy, label = 'Overall Accuracy')
        plt.plot(cfl_accuracy, label = 'CFL Accuracy')
        plt.plot(halogen_accuracy, label = 'Halogen Accuracy')
        plt.plot(incandescent_accuracy, label = 'Incandescent Accuracy')
        plt.plot(led_accuracy, label = 'LED Accuracy')
        plt.xticks(np.arange(0,len(k_list), 1), k_list.astype('str'))
        plt.xlabel('Value of \'k\' for KNN')
        plt.ylabel('Accuracy')
        plt.title(title)
        plt.legend()
        plt.show()

    '''
    this is a very specific plot; another plot for the BuildSys paper

    Description: plotting misclassification similarities between two types of light bulbs

    folder_name_0 should be for `halogen`
    folder_name_1 should be for 'incandescent'

    '''
    def ACam_plot_similar_BRFs(brf_KNN_model, ACam_path, folder_name_0, folder_name_1):
        csv_path_0 = os.path.join(ACam_path, folder_name_0)
        csv_path_1 = os.path.join(ACam_path, folder_name_1)

        cwd = os.getcwd()

        os.chdir(csv_path_0)
        file_list_0 = glob.glob('*.csv')

        h_once = True
        i_once = True

        halogen_LED_list = list()
        incan_LED_list = list()

        for csv_file in file_list_0:
            # print(csv_file)
            df = pd.read_csv(csv_file)

            # need this step because somehow the waveforms are flipped
            norm_waveform = abs(np.array(df['Intensity']) - 1)
            new_waveform = ACam.reconstruct_LIVE_ACam_waveform(norm_waveform)

            input_param = ACam.extract_features_ACam(new_waveform)
            output = brf_KNN_model.predict([input_param])[0]

            if output != 'Halogen':
                if output == 'Incandescent':
                    if h_once:
                        plt.plot(new_waveform, color='b', label='Halogen', alpha=0.5)
                        h_once = False
                    else:
                        plt.plot(new_waveform, color='b', alpha=0.5)
                if output == 'LED':
                    halogen_LED_list.append(new_waveform)

        os.chdir(csv_path_1)
        file_list_1 = glob.glob('*.csv')

        for csv_file in file_list_1:
            # print(csv_file)
            df = pd.read_csv(csv_file)

            # need this step because somehow the waveforms are flipped
            norm_waveform = abs(np.array(df['Intensity']) - 1)
            new_waveform = ACam.reconstruct_LIVE_ACam_waveform(norm_waveform)

            input_param = ACam.extract_features_ACam(new_waveform)
            output = brf_KNN_model.predict([input_param])[0]

            if output != 'Incandescent':
                if output == 'Halogen':
                    if i_once:
                        plt.plot(new_waveform, color='orange', label='Incandescent', alpha=0.5)
                        i_once = False
                    else:
                        plt.plot(new_waveform, color='orange', alpha=0.5)
                if output == 'LED':
                    incan_LED_list.append(new_waveform)

        font_size = 13

        plt.legend(fontsize=font_size, loc='lower center')
        plt.xlabel('Sample Number', fontsize=font_size)
        plt.xticks(np.arange(0, len(new_waveform)+1, step=20), fontsize=font_size)
        plt.ylabel('Normalized Intensity', fontsize=font_size)
        plt.yticks(np.arange(0, 1.1, step=0.25), fontsize=font_size)
        plt.tight_layout()
        plt.show()

        os.chdir(cwd)

        return halogen_LED_list, incan_LED_list

    '''
    plotting similarities between halogen, incandescent, and LED BRFs for buildsys paper
    '''
    def compare_incan_halogen_LED_plots(halogen_LED_list, incan_LED_list, LED_path):
        h_once = True
        i_once = True
        l_once = True

        cwd = os.getcwd()
        os.chdir(LED_path)
        led_folder_list = glob.glob('*')

        for brf in halogen_LED_list:
            if h_once:
                plt.plot(brf, color='b', label='Halogen', alpha=0.5)
                h_once = False
            else:
                plt.plot(brf, color='b', alpha=0.5)

        for brf in incan_LED_list:
            if i_once:
                plt.plot(brf, color='orange', label='Incandescent', alpha=0.5)
                i_once = False
            else:
                plt.plot(brf, color='orange', alpha=0.5)

        for led_folder in led_folder_list:
            waveform_list = brf_extraction(led_folder, 'double').brf_list
            smoothed = raw_waveform_processing.moving_average(raw_waveform_processing.savgol(waveform_list[1], define.savgol_window), define.mov_avg_w_size)
            nadir_indices = signal.find_peaks(-smoothed, distance = 750)[0]
            single_cycle = smoothed[:nadir_indices[0]]
            downsampled_single_cycle = raw_waveform_processing.normalize(signal.resample(single_cycle, 80))
            if l_once:
                plt.plot(downsampled_single_cycle, color='g', label='LED', alpha = 0.5)
                l_once = False
            else:
                plt.plot(downsampled_single_cycle, color='g', alpha = 0.5)

        font_size = 13
        plt.legend(fontsize=font_size, loc='lower center')
        plt.xlabel('Sample Number', fontsize=font_size)
        plt.xticks(np.arange(0, len(brf)+1, step=20), fontsize=font_size)
        plt.ylabel('Normalized Intensity', fontsize=font_size)
        plt.yticks(np.arange(0, 1.1, step=0.25), fontsize=font_size)
        plt.tight_layout()
        plt.show()
        # for brf in halogen_LED_list:
        #     plt.plot(brf)

    # FOR REDOING PAPER FIGURES WITH DIFFERENT FONT
    def graph_cm_type():
        bulb_types_list = list(['CFL', 'Halogen', 'Incandescent', 'LED'])

        confusion_matrix = np.zeros((4,4))
        confusion_matrix[0][0] = 1
        confusion_matrix[1][1] = 0.67
        confusion_matrix[1][2] = 0.33
        confusion_matrix[2][1] = 0.27
        confusion_matrix[2][2] = 0.73
        confusion_matrix[3][1] = 0.067
        confusion_matrix[3][2] = 0.033
        confusion_matrix[3][3] = 0.9

        # confusion_matrix[0][0] = 1
        # confusion_matrix[1][1] = 0.78
        # confusion_matrix[1][2] = 0.22
        # confusion_matrix[2][1] = 0.091
        # confusion_matrix[2][2] = 0.91
        # confusion_matrix[3][2] = 0.067
        # confusion_matrix[3][3] = 0.93

        # confusion_matrix = np.divide(prediction_matrix, total)
        fz = 12
        cmfz = 14
        lw = 2
        tick_size = 3
        df_cm = pd.DataFrame(confusion_matrix, index = [i for i in bulb_types_list], columns = [i for i in bulb_types_list])
        #(12,7) if just figure title
        # plt.figure(figsize = (9,9))
        # plt.figure()
        fig, ax = plt.subplots()

        sn.set(rc={'axes.facecolor':'cornflowerblue', 'figure.facecolor':'cornflowerblue'})
        res = sn.heatmap(data=df_cm, annot=True, annot_kws={'size': cmfz}, square=True, cbar=False, cmap='Blues')
        cbar = plt.colorbar(matplotlib.cm.ScalarMappable(cmap='Blues'))

        # sn.set(rc={'axes.facecolor':'limegreen', 'figure.facecolor':'limegreen'})
        # res = sn.heatmap(data=df_cm, annot=True, annot_kws={'size': cmfz}, square=True, cbar=False, cmap='Greens')
        # cbar = plt.colorbar(matplotlib.cm.ScalarMappable(cmap='Greens'), ax=ax)

        # sn.set(font_scale=200)

        cbar.outline.set_color('black')
        cbar.outline.set_linewidth(1)

        res.tick_params(left=True, bottom=True, size = tick_size)
        # for _, spine in res.spines.items():
        #     spine.set_visible(True)
        #     spine.set_linewidth(5)
        res.axhline(y = 0, color='k',linewidth = lw)
        res.axhline(y = df_cm.shape[1], color = 'k', linewidth = lw)
        res.axvline(x = 0, color = 'k', linewidth = lw)
        res.axvline(x = df_cm.shape[0], color = 'k', linewidth = lw)

        # cbar = fig.colorbar(res, ticks=[0,1])

        cbar.ax.tick_params(size = 4, labelsize=fz)
        cbar.outline.set_visible(True)
        plt.xlabel('Predicted Labels', fontsize = fz)
        plt.ylabel('True Labels', fontsize = fz)
        plt.xticks(fontsize = fz)
        plt.yticks(va = 'center', rotation=0, fontsize=fz)
        plt.tight_layout()
        plt.show()

if __name__ == '__main__':
    plots.graph_cm_type()


import json
import logging
import os

from babel import dates
from google.appengine.api import users as gae_users
import jinja2
from mcfw.rpc import serialize_complex_value
from rogerthat.bizz import channel
from rogerthat.consts import DEBUG
from rogerthat.rpc import users
from rogerthat.service.api import system
from rogerthat.translations import DEFAULT_LANGUAGE
from shop.constants import LOGO_LANGUAGES
from solution_server_settings import get_solution_server_settings
from solutions import translate, translations, COMMON_JS_KEYS
from solutions.common import SOLUTION_COMMON
from solutions.common.bizz import SolutionModule
from solutions.common.bizz.settings import SLN_LOGO_WIDTH, SLN_LOGO_HEIGHT
from solutions.common.consts import UNIT_PIECE, UNIT_LITER, UNIT_KG, UNIT_GRAM, UNIT_HOUR, UNIT_MINUTE, \
    ORDER_TYPE_SIMPLE, ORDER_TYPE_ADVANCED, UNITS, UNIT_SYMBOLS, UNIT_DAY, UNIT_PERSON, UNIT_PLATTER, UNIT_SESSION
from solutions.common.dal import get_solution_settings, get_solution_email_settings
from solutions.common.models.properties import MenuItem
from solutions.common.to import SolutionEmailSettingsTO
from solutions.djmatic import JUKEBOX_SERVER_API_URL, SOLUTION_DJMATIC
from solutions.djmatic.dal import get_djmatic_profile
from solutions.jinja_extensions import TranslateExtension
import webapp2

JINJA_ENVIRONMENT = jinja2.Environment(loader=jinja2.FileSystemLoader([os.path.join(os.path.dirname(__file__), '..', 'templates'),
                                                                       os.path.join(os.path.dirname(__file__), '..', '..', 'common', 'templates')]),
                                       extensions=[TranslateExtension])

class DJMaticHomeHandler(webapp2.RequestHandler):

    def _get_days(self, sln_settings):
        return [(k, v.capitalize()) for k, v in dates.get_day_names('wide', locale=sln_settings.main_language or DEFAULT_LANGUAGE).items()]

    def _get_months(self, sln_settings, width):
        return [v.capitalize() for _, v in dates.get_month_names(width, locale=sln_settings.main_language or DEFAULT_LANGUAGE).items()]

    def _get_day_str(self, sln_settings, day):
        return dates.get_day_names('wide', locale=sln_settings.main_language or DEFAULT_LANGUAGE)[day].capitalize()

    def _get_week_days(self, sln_settings):
        return [self._get_day_str(sln_settings, day) for day in [6, 0, 1, 2, 3, 4, 5]]

    def get(self):
        service_user = users.get_current_user()
        if not service_user:
            self.redirect("/")
            return
        sln_settings = get_solution_settings(service_user)
        if not sln_settings or sln_settings.solution != SOLUTION_DJMATIC:
            self.redirect("/")
            return

        tmpl_params = {'language': DEFAULT_LANGUAGE,
                       'debug': DEBUG,
                       'currency': sln_settings.currency,
                       'service_user_email': service_user.email()}
        templates = dict()
        for tmpl in ('menu_additem', 'menu', 'menu_editdescription', 'menu_edit_image', 'holiday_holiday',
                     'inbox_messages', 'inbox_detail_messages',
                     'events_add', 'events_add_dates', 'events', 'events_events', 'events_settings', 'events_calendar_settings', 'events_guests_modal',
                     'events_guests_table', 'events_uitcalendar_settings',
                     'broadcast_types', 'broadcast_schedule', 'broadcast_schedule_items', 'addattachment',
                     'settings/try_publish_changes', 'settings/settings_branding', 'settings/settings_branding_preview', 'settings/upload_image'):
            templates[tmpl] = JINJA_ENVIRONMENT.get_template(tmpl + '.html').render(tmpl_params)
        templates = json.dumps(templates)

        bulk_invite_message = translate(sln_settings.main_language, SOLUTION_COMMON, "settings-bulk-invite-message",
                                        app_name=system.get_identity().app_names[0])

        jinja_template = JINJA_ENVIRONMENT.get_template('index.html')

        days = self._get_days(sln_settings)
        day_flags = [(pow(2, day_num), day_name) for day_num, day_name in days ]
        months = self._get_months(sln_settings, 'wide')
        months_short = self._get_months(sln_settings, 'abbreviated')
        week_days = self._get_week_days(sln_settings)
        all_translations = {key: translate(sln_settings.main_language, SOLUTION_COMMON, key) for key in
                            translations[SOLUTION_COMMON]['en']}
        for key in COMMON_JS_KEYS:
            all_translations[key] = translate(sln_settings.main_language, SOLUTION_COMMON, COMMON_JS_KEYS[key])

        consts = {
            'UNIT_PIECE': UNIT_PIECE,
            'UNIT_LITER': UNIT_LITER,
            'UNIT_KG': UNIT_KG,
            'UNIT_GRAM': UNIT_GRAM,
            'UNIT_HOUR': UNIT_HOUR,
            'UNIT_MINUTE': UNIT_MINUTE,
            'UNIT_DAY': UNIT_DAY,
            'UNIT_PERSON': UNIT_PERSON,
            'UNIT_SESSION': UNIT_SESSION,
            'UNIT_PLATTER': UNIT_PLATTER,
            'ORDER_TYPE_SIMPLE': ORDER_TYPE_SIMPLE,
            'ORDER_TYPE_ADVANCED': ORDER_TYPE_ADVANCED,
            'ORDER_ITEM_VISIBLE_IN_MENU': MenuItem.VISIBLE_IN_MENU,
            'ORDER_ITEM_VISIBLE_IN_ORDER': MenuItem.VISIBLE_IN_ORDER
        }
        params = {
            'language': DEFAULT_LANGUAGE,
            'solution': sln_settings.solution,
            'logo_languages': LOGO_LANGUAGES,
            'debug': DEBUG,
            'templates': templates,
            'service_user_email': service_user.email().encode("utf-8"),
            'service_name': sln_settings.name,
            'has_multiple_locations': False,
            'sln_settings': sln_settings,
            'days': days,
            'day_flags': day_flags,
            'months': months,
            'months_short': months_short,
            'week_days': week_days,
            'djmatic_profile': get_djmatic_profile(service_user),
            'jukebox_server_api': JUKEBOX_SERVER_API_URL,
            'bulk_invite_message': bulk_invite_message,
            'SolutionModule': SolutionModule,
            'email_settings': json.dumps(
                serialize_complex_value(
                    SolutionEmailSettingsTO.fromModel(get_solution_email_settings(), service_user),
                    SolutionEmailSettingsTO, False)),
            'SLN_LOGO_WIDTH': SLN_LOGO_WIDTH,
            'SLN_LOGO_HEIGHT': SLN_LOGO_HEIGHT,
            'UNITS': json.dumps(UNITS),
            'UNIT_SYMBOLS': json.dumps(UNIT_SYMBOLS),
            'CONSTS': consts,
            'CONSTS_JSON': json.dumps(consts),
            'modules': json.dumps(sln_settings.modules),
            'translations': json.dumps(all_translations)
        }

        channel.append_firebase_params(params)
        self.response.out.write(jinja_template.render(params))

class DJMaticOverviewHandler(webapp2.RequestHandler):

    def get(self):
        solution_server_settings = get_solution_server_settings()
        VALID_USERS = [gae_users.User(email) for email in solution_server_settings.djmatic_overview_emails]
        user = gae_users.get_current_user()
        if user and user in VALID_USERS:

            templates = dict()
            for tmpl in ['djmatic_overview_items']:
                templates[tmpl] = JINJA_ENVIRONMENT.get_template(tmpl + '.html').render({})
            templates = json.dumps(templates)

            jinja_template = JINJA_ENVIRONMENT.get_template('djmatic_overview.html')
            self.response.out.write(jinja_template.render({"templates": templates}))
        else:
            if user:
                logging.warn("Untrusted google user in DJMaticOverviewHandler: %s" % user)
            self.abort(404)