# -*- coding: utf-8 -*-
import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt
import plotly
from plotly import graph_objs as go
from plotly.graph_objs import *
from flask import Flask
import pandas as pd
import numpy as np
import os
import copy

app = dash.Dash(__name__)
server = app.server

# API keys and datasets
mapbox_access_token = 'pk.eyJ1IjoibW9oYW1lZGRoYSIsImEiOiJjanJtZmRpeWYwaDhnNGFvNXRqZDNhbmJjIn0.IIpYluC9Mgl4PZkhAMriQQ'
map_data = pd.read_csv('https://raw.githubusercontent.com/kasamoh/Dash_app/master/sonic_dash/SONYC_Dataset.csv')

map_data.drop("Unnamed: 0", 1, inplace=True)

# Boostrap CSS.
app.css.append_css({'external_url': 'https://cdn.rawgit.com/plotly/dash-app-stylesheets/2d266c578d2a6e8850ebce48fdb52759b2aef506/stylesheet-oil-and-gas.css'})  # noqa: E501

layout = dict(
    autosize=True,
    height=500,
    font=dict(color="#191A1A"),
    titlefont=dict(color="#191A1A", size='14'),
    margin=dict(
        l=35,
        r=35,
        b=35,
        t=45
    ),
    hovermode="closest",
    plot_bgcolor='#fffcfc',
    paper_bgcolor='#fffcfc',
    legend=dict(font=dict(size=10), orientation='h'),
    title='Each dot is an NYC Middle School eligible for SONYC funding',
    mapbox=dict(
        accesstoken=mapbox_access_token,
        style="light",
        center=dict(
            lon=-73.91251,
            lat=40.7342
        ),
        zoom=10,
    )
)

# Controls (dropdowns)
group = ['All']
group = group + ['Low', 'Medium', 'High', 'Very High']
group_class = [{'label': str(item),
                      'value': str(item)}
                     for item in group]


# Creating layouts for datatable
layout_right = copy.deepcopy(layout)
layout_right['height'] = 300
layout_right['margin-top'] = '20'
layout_right['font-size'] = '12'

mp_max = map_data['Need Score'].max()
mp_min = map_data['Need Score'].min()

# Components style
def color_scale(md, selected_row_indices=[]):
    color = []
    max_score = mp_max
    min_score = mp_min
    for row in md['Need Score']:
        scale = (row - mp_min)/(mp_max - mp_min)
        if scale <= 0.06:
            color.append("#26EC04")
        elif scale <= 0.12:
            color.append("#8FDB44")
        elif scale <= 0.18:
            color.append("#A5D643")
        elif scale <= 0.24:
            color.append("#B8D343")
        elif scale <= 0.30:
            color.append("#B8D343")
        elif scale <= 0.36:
            color.append("#DBCD44")
        elif scale <= 0.42:
            color.append("#E1CD44")
        elif scale <= 0.48:
            color.append("#F0CB45")
        elif scale <= 0.54:
            color.append("#F3C644")
        elif scale <= 0.60:
            color.append("#F2BE41")
        elif scale <= 0.66:
            color.append("#F0AE3D")
        elif scale <= 0.72:
            color.append("#EFA73B")
        elif scale <= 0.78:
            color.append("#EE9F39")
        elif scale <= 0.84:
            color.append("#ED8934")
        elif scale <= 0.90:
            color.append("#E95729")
        else:
            color.append("#FD0101")
    for i in selected_row_indices:
        color[i] = '#1500FA'
    return color

def gen_map(map_data):
    # groupby returns a dictionary mapping the values of the first field
    # 'classification' onto a list of record dictionaries with that
    # classification value.
    return {
        "data": [
                {
                    "type": "scattermapbox",
                    "lat": list(map_data['Latitude']),
                    "lon": list(map_data['Longitude']),
                    "text": list(map_data['Need Score']),
                    "mode": "markers",
                    "name": list(map_data['Location Name']),
                    "marker": {
                        "size": 6,
                        "opacity": 1.0,
                        "color": color_scale(map_data)
                    }
                }
            ],
        "layout": layout
    }


# Layout
app.layout = html.Div([
    # Title - Row
    html.Div(
        [
            html.H1(
                'SONYC Sitting Model',
                style={'font-family': 'Helvetica',
                       "margin-top": "25",
                       "margin-bottom": "0"},
                className='eight columns',
            ),
            html.Img(
                src="http://static1.squarespace.com/static/546fb494e4b08c59a7102fbc/t/591e105a6a496334b96b8e47/1497495757314/.png",
                className='two columns',
                style={
                    'height': '9%',
                    'width': '9%',
                    'float': 'right',
                    'position': 'relative',
                    'padding-top': 10,
                    'padding-right': 0
                },
            ),
            html.P(
                'Testing mapbox with flask and dash',
                style={'font-family': 'Helvetica',
                       "font-size": "120%",
                       "width": "80%"},
                className='eight columns',
            ),
        ],
        className='row'
    ),

    # Selectors
    html.Div(
        [
            html.Div(
                [
                    html.P('Choose Borroughs:'),
                    dcc.Checklist(
                            id = 'Boroughs',
                            options=[
                                {'label': 'Manhattan', 'value': 'MANHATTAN'},
                                {'label': 'Bronx', 'value': 'BRONX'},
                                {'label': 'Queens', 'value': 'QUEENS'},
                                {'label': 'Brooklyn', 'value': 'BROOKLYN'},
                                {'label': 'Staten Island', 'value': 'STATEN ISLAND'}
                            ],
                            values=['MANHATTAN', 'QUEENS', 'BRONX', 'BROOKLYN', 'STATEN ISLAND'],
                            labelStyle={'display': 'inline-block'}
                    ),
                ],
                className='six columns',
                style={'margin-top': '10'}
            ),
            html.Div(
                [
                    html.P('DOE Need:'),
                    dcc.Dropdown(
                        id='DOE',
                        options= group_class,
                        multi=False,
                        value='All'
                    )
                ],
                className='two columns',
                style={'margin-top': '10'}
            ),
            html.Div(
                [
                    html.P('Crime BIN (group):'),
                    dcc.Dropdown(
                        id='Crime',
                        options= group_class,
                        multi=False,
                        value='All'
                    )
                ],
                className='two columns',
                style={'margin-top': '10'}
            ),
            html.Div(
                [
                    html.P('Obesity BIN (group):'),
                    dcc.Dropdown(
                        id='Obesity',
                        options= group_class,
                        multi=False,
                        value='All'
                    )
                ],
                className='two columns',
                style={'margin-top': '10'}
            )
        ],
        className='row'
    ),

    # Map + table + Histogram
    html.Div(
        [
            html.Div(
                [
                    dcc.Graph(id='map-graph',
                              animate=True, 
                              style={'margin-top': '20'})
                ], className = "six columns"
            ),
            html.Div(
                [
                    dt.DataTable(
                        rows=map_data.to_dict('records'),
                        columns=map_data.columns,
                        row_selectable=True,
                        filterable=True,
                        sortable=True,
                        selected_row_indices=[],
                        id='datatable'),
                ],
                style=layout_right,
                className="six columns"
            ),
            html.Div(
                [
                    dcc.Graph(id="histogram")
                ],className="twelve columns")
        ], className="row"
    )
], className='ten columns offset-by-one')

# Callbacks and functions
@app.callback(
    Output('datatable', 'rows'),
    [dash.dependencies.Input('Boroughs', 'values'),
    dash.dependencies.Input('DOE', 'value'),
    dash.dependencies.Input('Crime', 'value'),
    dash.dependencies.Input('Obesity', 'value')])
def update_selected_row_indices(boroughs, doe, crime, obesity):
    map_aux = map_data.copy()

    # Boroughs filter
    map_aux = map_aux[map_aux['City'].isin(boroughs)]

    # DOE filter
    if doe == 'Low':
        map_aux = map_aux[map_aux['DOE Need (with Truancy)'] <= 0.5]
    if doe == 'Medium':
        map_aux = map_aux[(map_aux['DOE Need (with Truancy)'] > 0.5) & \
                          (map_aux['DOE Need (with Truancy)'] <= 1.0)]
    if doe == 'High':
        map_aux = map_aux[(map_aux['DOE Need (with Truancy)'] > 1.0) & \
                          (map_aux['DOE Need (with Truancy)'] <= 1.5)]
    if doe == 'Very High':
        map_aux = map_aux[map_aux['DOE Need (with Truancy)'] > 1.5]

    # Crime filter
    if crime == 'Low':
        map_aux = map_aux[map_aux['Crime'] <= 0.1]
    if crime == 'Medium':
        map_aux = map_aux[(map_aux['Crime'] > 0.1) & \
                          (map_aux['Crime'] <= 0.25)]
    if crime  == 'High':
        map_aux = map_aux[(map_aux['Crime'] > 0.25) & \
                          (map_aux['Crime'] <= 0.4)]
    if crime  == 'Very High':
        map_aux = map_aux[map_aux['Crime'] > 0.4]

    # Obesity filter
    if obesity == 'Low':
        map_aux = map_aux[map_aux['Obesity'] <= 15]
    if obesity == 'Medium':
        map_aux = map_aux[(map_aux['Obesity'] > 15) & \
                          (map_aux['Obesity'] <= 27.5)]
    if obesity  == 'High':
        map_aux = map_aux[(map_aux['Obesity'] > 27.5) & \
                          (map_aux['Obesity'] <= 35.0)]
    if obesity  == 'Very High':
        map_aux = map_aux[map_aux['Obesity'] > 35.0]

    rows = map_aux.to_dict('records')
    return rows

@app.callback(
    Output('datatable', 'selected_row_indices'),
    [Input('histogram', 'selectedData')],
    [State('datatable', 'selected_row_indices')])
def update_selected_row_indices_hist(selectedData, selected_row_indices):
    if selectedData:
        selected_row_indices = []
        for point in selectedData['points']:
            selected_row_indices.append(point['pointNumber'])
    return selected_row_indices


@app.callback(
    Output('histogram', 'figure'),
    [Input('datatable', 'rows'),
     Input('datatable', 'selected_row_indices')])
def update_figure(rows, selected_row_indices):
    dff = pd.DataFrame(rows)
    layout = go.Layout(
        bargap=0.05,
        bargroupgap=0,
        barmode='group',
      #  margin=Margin(l=50, r=10, t=0, b=100),
        showlegend=False,
        height=250,
        dragmode="select",
        xaxis=dict(
            showgrid=False,
            nticks=50,
            fixedrange=False
        ),
        yaxis=dict(
            showticklabels=True,
            showgrid=False,
            fixedrange=False,
            rangemode='nonnegative',
            zeroline=True
        )
    )


    data = Data([
         go.Bar(
             x=dff['Location Name'],
             y=dff['Need Score'],
             marker = {'color': color_scale(dff, selected_row_indices)}
           #  hoverinfo=dff['Location Name']
         )
     ])

    return go.Figure(data=data, layout=layout)



@app.callback(
    Output('map-graph', 'figure'),
    [Input('datatable', 'rows'),
     Input('datatable', 'selected_row_indices')])
def map_selection(rows, selected_row_indices):
    aux = pd.DataFrame(rows)
    temp_df = aux.ix[selected_row_indices, :]
    if len(selected_row_indices) == 0:
        return gen_map(aux)
    return gen_map(temp_df)


if __name__ == '__main__':
    app.run_server()