from __future__ import print_function

import boto3
import json
import logging
import requests
import http.client, urllib.request, urllib.parse, urllib.error, base64
import simplejson as json
import xml.etree.ElementTree as ET

logger = logging.getLogger()
logger.setLevel(logging.INFO)
sns = boto3.client('sns')

# Global Variables
PHONE_NUMBER = '###'
DARK_SKY_KEY = '###'
DARK_SKY_COORD = '###'
METRO_API_KEY = '###'
METRO_STATION_ID = '###'
BIKESHARE_XML_PATH = '/tmp/bikes.xml'
BIKESHARE_STATIONS = ['###']
COIN_LIST = ['###']

# Metro API URL parameters
headers = {
    # Using demo API key
    'api_key': METRO_API_KEY,
}
params = urllib.parse.urlencode({
})

# Triggered upon call of the Lambda function
def lambda_handler(event, context):
    logger.info('Received event: ' + json.dumps(event))
    #message = 'Hello from your IoT Button %s. Here is the full event: %s' % (event['serialNumber'], json.dumps(event))
    message = build_weather_blurb(get_weather()) + "\n" + get_shaw_trains() + "\n" + get_capital_bikeshare_status() + "\n" + get_prices(get_coins(), COIN_LIST)
    sns.publish(PhoneNumber=PHONE_NUMBER, Message=message)
    logger.info('SMS has been sent to ' + PHONE_NUMBER)

# Get next 2 southbound trains at Shaw
def get_shaw_trains():
    trains = get_trains(METRO_STATION_ID)
    south_trains = sort_southbound_trains(trains)
    return return_southbound_trains(south_trains)

# Retrieve the incoming trains at a given station
def get_trains(station_id):
    try:
        conn = http.client.HTTPSConnection('api.wmata.com')
        conn.request("GET", "/StationPrediction.svc/json/GetPrediction/" + station_id + "?%s" % params, "{body}", headers)
        response = conn.getresponse()
        data = response.read()
        conn.close()
    except Exception as e:
        print("[Errno {0}] {1}".format(e.errno, e.strerror))
    parsed_json = json.loads(data)
    trains = parsed_json["Trains"]
    return trains

# Return the next 2 southbound trains at a given station
def sort_southbound_trains(trains):
    south_trains = []
    count = 0
    for train in trains:
        if train['Group'] == '2' and count < 2:
            south_trains.append(train)
            count += 1
    return south_trains

# Print the south bound trains at a given station
def return_southbound_trains(south_trains):
    south = ""
    if len(south_trains) == 0:
        return "\n"
    for train in south_trains:
        south += train['Min'] + " minutes to " + train['Destination'] + " (" + train['Line'] + ")\n"
    return south

# Download the latest XML of Capital Bikeshare data
def load_bikeshare_XML():
    url = 'https://feeds.capitalbikeshare.com/stations/stations.xml'
    data = requests.get(url)
    # Save the XML file into /tmp so Lambda can access it
    with open(BIKESHARE_XML_PATH, 'wb') as f:
        f.write(data.content)
       
# Return station information for stations: 145 (7th and R) and 47 (7th and T)
def parse_bikeshare_stations(xmlfile):
    # create element tree object
    tree = ET.parse(xmlfile)
    # get root element
    root = tree.getroot()
    selected_stations = []
    for s in root.findall("station"):
        station = {}
        for child in s:
            station[child.tag] = child.text
        if station["id"] in BIKESHARE_STATIONS:
            selected_stations.append(station)
    return selected_stations

# Return a string containing updates for the stations passed
def return_shaw_bikeshare_stations(list):
    response = ""
    for station in list:
        response += station['name'] + ": " + station["nbBikes"] + " bikes, " + station["nbEmptyDocks"] + " docks.\n"
    return response

# Trigger the download, parsing, and building of the Bikeshare status
def get_capital_bikeshare_status():
    load_bikeshare_XML()
    stations = parse_bikeshare_stations(BIKESHARE_XML_PATH)
    return return_shaw_bikeshare_stations(stations)

# Download a JSON of weather data from Dark Sky at the given coordinates
def get_weather():
    weather = {}
    try:
        conn = http.client.HTTPSConnection('api.darksky.net')
        conn.request("GET", "/forecast/" + DARK_SKY_KEY + "/%s" % DARK_SKY_COORD)
        response = conn.getresponse()
        data = response.read()
        conn.close()
    except Exception as e:
        print("[Errno {0}] {1}".format(e.errno, e.strerror))
    parsed_json = json.loads(data)
    return parsed_json

# Return a string response for the current weather
def build_weather_blurb(weather):
    response = ""
    response += "Weather: " + weather["currently"]["summary"] + "\n"
    response += "Temperature: " + str(weather["currently"]["apparentTemperature"]) + "\u00b0\n"
    response += "Upcoming: " + weather["minutely"]["summary"] + "\n"
    response += "Today: " + weather["hourly"]["summary"] + "\n"
    return response

# Download a JSON of crypto prices from CoinMarketCap
def get_coins():
    weather = {}
    try:
        conn = http.client.HTTPSConnection('api.coinmarketcap.com')
        conn.request("GET", "/v1/ticker/")
        response = conn.getresponse()
        data = response.read()
        conn.close()
    except Exception as e:
        print("[Errno {0}] {1}".format(e.errno, e.strerror))
    parsed_json = json.loads(data)
    return parsed_json

# Get list of coin symbols and prices in market cap order
def get_prices(coins, my_list):
    response = ""
    for coin in coins:
        if coin['symbol'] in my_list:
            response += coin['symbol'] + ": $" + coin['price_usd'] + "\n"
    return response