"""
 Tool Name:  DownloadGNIS
 Description: Downloads GNIS data by state using the National Map API.
 Author: Patrick Longley (plongley@usgs.gov)
 Created: 08/11/2020
 Language: Written in python3 (arcpro). Modified to also work in python2 (arcmap).
 History: 
"""

# IMPORTS
import urllib
import os
import sys
import arcpy
from zipfile import ZipFile
import pandas as pd
import numpy as np
import wbd_params
import wbd_f

#PYTHON 2/3 issues
python_version = sys.version_info.major

class DownloadGNIS(object):
    """
    Downloads GNIS data by state using the National Map API.

    Args:
        statenames (str): statenames (more than one can be entered).
        gnis_gdb (str):  Godatabase where GNIS data will be saved.
        spatial_reference (ESRI spatial reference object): Spatial reference data will be saved in.

    Outputs:
        returns: None
        output parameter: New feature class and ESRI table added to geodatabase.
    """
    def __init__(self):
        """
        Initialize variables
        """
        self.label       = "Download GNIS data"
        self.description = "This tool downloads GNIS data by state using the National Map API."
        self.callfrom_pyt = True
        self.category = 'Download data'

    def getParameterInfo(self):
        """
        Define the parameters for use in arcmap/pro.
        """
        if python_version == 3:
            statenames = wbd_params.statenames_py3
        elif python_version == 2:
            statenames = wbd_params.statenames_py2
        params = [statenames,
                  wbd_params.gnis_gdb,
                  wbd_params.spatial_reference]
        return params

    def updateMessages(self, params):
        """
        Modify the messages created by internal validation for each tool
        parameter.This method is called after internal validation. 
        """
        if params[1].altered:
            if not params[1].valueAsText.endswith('.gdb'):
                message = 'Must enter a geodatabase.'
                params[1].setErrorMessage(message)

    def execute(self, params, messages):
        """
        Loops through states and downloads GNIS data for each state.
        """
        if self.callfrom_pyt:
            self.state_names = params[0].valueAsText
            self.gnis_gdb = params[1].valueAsText
            self.sr = params[2].valueAsText
        else:
            self.state_names = params[0]
            self.gnis_gdb = params[1]
            self.sr = params[2]
        self.state_names = self.state_names.replace(" ", "").split(';')
        self.state_abbreviations = wbd_f.state_abrev(self.state_names)
        for state in self.state_abbreviations:
            # download data as table
            url = r'https://geonames.usgs.gov/docs/stategaz/{}_Features.zip'.format(state)
            folder = os.path.dirname(self.gnis_gdb)
            zip_folder = os.path.join(folder, state.upper() + '_gnis.zip')
            urllib.request.urlretrieve(url, zip_folder)
            with ZipFile(zip_folder, 'r') as zip_obj:
                fname = zip_obj.namelist()[0]
                zip_obj.extractall(folder)
                gnis_fpath = os.path.join(folder, fname)
            # convert to panda dataframe
            df = pd.read_table(gnis_fpath, delimiter='|', encoding='utf8')
            cols = df.columns
            df = df.rename(columns={cols[0]: "FEATURE_ID"})
            cols = tuple(df.columns)
            # convert to numpy array
            arr = np.array(np.rec.fromrecords(df.values))
            fields = df.dtypes.index.tolist()
            arr.dtype.names = tuple(fields)
            table = os.path.join(os.path.dirname(self.gnis_gdb), fname.strip('.txt') + '_table')
            # convert to ESRI table
            try:
                arcpy.da.NumPyArrayToTable(arr, table)
            except RuntimeError:
                pass
            # convert to feature class
            out_fc = os.path.join(self.gnis_gdb, fname.strip('.txt'))
            if not arcpy.Exists(out_fc):
                in_sr = arcpy.SpatialReference('NAD 1983')
                if self.sr:
                    out_sr = arcpy.SpatialReference(self.sr)
                else:
                    out_sr = in_sr
                arcpy.ConvertCoordinateNotation_management(table,
                                                        out_fc,
                                                        'PRIM_LONG_DEC',
                                                        'PRIM_LAT_DEC',
                                                        'DD_2',
                                                        'UTM zones',
                                                        spatial_reference=out_sr,
                                                        in_coor_system=in_sr)
            
if __name__ == '__main__':
    """
    Execute as standalone script.
    """
    states = 'Alaska'
    gdb = r'C:\GIS_Project\gnis_data\gnis_data.gdb'
    sr = None
    params = (states, gdb, sr)
    download_gnis = DownloadGNIS()
    download_gnis.callfrom_pyt = False
    download_gnis.execute(params, None)

