"""Loads twitter user info (json format) and writes geojson point for each user

Requires gecoding to change city/state to lat/lon
On turtleland2, runs in conda env "minerva-dev", which has geojson and geopy
"""
from __future__ import print_function
from builtins import input

import argparse
import json
import os
import time

import geojson
import geopy

#NOMINATIM_DOMAIN = 'nominatim.openstreetmap.org'
NOMINATIM_DOMAIN = '192.168.30.198:9003/'  # Thanks Doruk

class Converter:
    ''''''
    def __init__(self, options):
        ''''''
        self.options = options
        self.input_json = []
        self.feature_collection = None


    def load_input(self):
        '''Loads and parses input file
        '''
        if not options.input_filename:
            raise Exception('No input_filename specified in options')

        with open(self.options.input_filename) as f:
            line = f.readline()
            while line:
                data = json.loads(line)
                self.input_json.append(data)
                line = f.readline()

        if not self.input_json:
            raise Exception('Input file missing, empty, or unreadable ({})' \
                .format(self.options.input_filename))
        print('Number of input posts: {}'.format(len(self.input_json)))


    def count_location_data(self):
        ''''''
        count = 0
        loc_count = 0
        city_count = 0
        county_count = 0
        state_count = 0
        country_count = 0
        us_count = 0
        for user in self.input_json:
            # if count < 15:
            #     print('{}'.format(user))

            count += 1
            geo_loc = user.get('geo_loc')
            if not geo_loc:
                continue
            loc_count += 1


            country = geo_loc.get('country')
            if not country:
                continue

            state = geo_loc.get('state')
            county = geo_loc.get('county')
            city = geo_loc.get('city')


            if country == 'United States':
                us_count += 1

            if city:
                city_count += 1
                continue

            # Of the remaining...
            if county:
                county_count += 1
                continue

            if state:
                state_count += 1
                continue

            if country:
                country_count += 1
                continue
            # new_point = geojson.Point((longitude, latitude))
            # new_feature = geojson.Feature(geometry=new_point)
            # feature_list.append(new_feature)

        print('Number of users: {}'.format(count))
        print('Number of users with geo_loc: {}'.format(loc_count))
        print('Number of users with city: {}'.format(city_count))
        print('Number of users with county: {}'.format(county_count))
        print('Number of users with state: {}'.format(state_count))
        print('Number of users with country: {}'.format(country_count))
        print('Number of users with US as country: {}'.format(us_count))

        # self.feature_collection = geojson.FeatureCollection(feature_list)

    def build_geojson(self):
        ''''''
        feature_list = list()

        from geopy.geocoders import Nominatim
        geolocator = Nominatim(domain=NOMINATIM_DOMAIN, scheme='http')

        query = dict()
        for i,user in enumerate(self.input_json):
            time.sleep(0.5)

            if (i % 10) == 0:
                print('{:6d} {}'.format(i, user))
                time.sleep(1.0)

            geo_loc = user.get('geo_loc')
            if not geo_loc:
                continue

            country = geo_loc.get('country')
            state = geo_loc.get('state')
            county = geo_loc.get('county')
            city = geo_loc.get('city')

            if not city and not county:
                continue

            query.clear()
            query['country'] = country
            query['state'] = state
            if county:
                query['county'] = county
            if city:
                query['city'] = city

            # Get location with retries
            for t in range(3):
                try:
                    location = geolocator.geocode(query)
                except geopy.exc.GeocoderTimedOut as timeout:
                    print('{} Timeout'.format(i))
                    location = None
                    time.sleep(2.5)
                    continue
                except Exception as ex:
                    print('input {}  {}: {}'.format(i, type(ex), ex))
                    reply = input('Should I continue (N/y)?  ')
                    if not reply.lower().startswith('y'):
                        location = None
                        print('Current item number: {}'.format(i))
                        break

            if not location:
                continue

            # if (i % 10) == 0:
            #     print('{:6d} latlon {} {}'.format(i, location.latitude, location.longitude))

            new_point = geojson.Point((location.longitude, location.latitude))
            properties = dict()
            properties.update(query)
            properties['user_id'] = user.get('user_id')
            properties['id'] = geo_loc.get('id')
            properties['known'] = geo_loc.get('known')
            new_feature = geojson.Feature(geometry=new_point, properties=properties)
            feature_list.append(new_feature)

            if self.options.limit and i > self.options.limit:
                break

        print('Number of locations: {}'.format(len(feature_list)))
        self.feature_collection = geojson.FeatureCollection(feature_list)


    def write_output(self):
        ''''''
        with open(self.options.output_filename, 'w') as f:
            geojson.dump(self.feature_collection, f)
            f.write('\n')


if __name__ == '__main__':
    description = 'Generate geojson file from twitter user info'
    parser = argparse.ArgumentParser(description=description)
    parser.add_argument('-i', '--input_filename', required=True, \
        help='Input file (json)')
    parser.add_argument('-o', '--output_filename', help='Output filename (geojson)')
    parser.add_argument('-l', '--limit', type=int, help='Limit number of items processed')
    parser.add_argument('-f', '--offset', type=int, help='Starting item number')

    options = parser.parse_args()
    print(options)
    converter = Converter(options)

    print('Loading input file {}'.format(options.input_filename))
    converter.load_input()

    print('Processing')
    converter.count_location_data()
    converter.build_geojson()

    if options.output_filename:
        print('Writing output file {}'.format(options.output_filename))
        converter.write_output()
