#!/usr/bin/env python
# -*- coding: utf-8 -*-

#WRITTEN BY DENE BOWDALO

###------------------------------------------------------------------------------------###
###IMPORT MODULES
###------------------------------------------------------------------------------------###

import bisect
import copy
import crossnetwork_processing_modules
import datetime
import numpy as np
import pandas as pd
import standardisation_modules

###------------------------------------------------------------------------------------###
###------------------------------------------------------------------------------------###

#modules that applies each of modular classification checks to data from each site
def do_classifications(metadata,data):

    #-----------------------------------------------------#
    #HIGH ALTITUDE CLASSIFICATIONS
    #-----------------------------------------------------#
    
    #High Altitude - Metadata Altitude 
    data = high_altitude_classification_by_metadata_altitude(metadata,data)

    #High Altitude - Metadata Derived
    data = high_altitude_classification_by_standardised_terrain_metadata(metadata,data)
    
    #High Altitude - ETOPO1 
    #data = high_altitude_classification_by_ETOPO1(metadata,data)
    
    #High Altitude - Iwahashi Global Landform Classification 
    #data = high_altitude_classification_by_Iwahashi(metadata,data)
    
    #High Altitude - Meybeck Global Landform Classification
    #data = high_altitude_classification_by_Meybeck(metadata,data)

    #-----------------------------------------------------#
    #NEAR COAST CLASSIFICATIONS
    #-----------------------------------------------------#
    
    #Near Coast - Metadata Derived
    data = near_coast_classification_by_standardised_terrain_metadata(metadata,data)
    
    #Near Coast - GSFC
    #data = near_coast_classification_by_GSFC(metadata,data)
 
    #-----------------------------------------------------#
    #RURAL/URBAN CLASSIFICATIONS
    #-----------------------------------------------------#
    
    #rural/urban classifications using standardised network provided metadata
    data = rural_urban_classification_by_standardised_metadata(metadata,data)
    
    #rural/urban classifications using ANTHROME classification
    #data = rural_urban_classification_by_anthrome(metadata,data)
    
    #rural/urban classifications using TOAR classification
    #data = rural_urban_classification_by_TOAR(metadata,data)
    
    #rural/urban classifications using Joly-Peuch classification
    #data = rural_urban_classification_by_Joly_Peuch(metadata,data)
    
    
    return data

###------------------------------------------------------------------------------------###
###------------------------------------------------------------------------------------###
#CLASSIFICATION MODULES

#Check for high altitude stations using network provided altitude + sampling height information
#check is done by adding station altitude + sampling height to produce a measurement height, and this is checked to see if it is >= 1500 metres (relative to mean sea level)
#if no sampling height is available, only station altitude is used. If no altitude, check is not done.

def high_altitude_classification_by_metadata_altitude(metadata,data):
    
    high_altitude_limit = 1500 #1500 metres relative to mean sea level
    
    alts = metadata['altitude']
    sampling_heights = metadata['sampling_height']
    update_metadata_stamp = metadata['meta_update_stamp']
    
    measurement_alts = copy.deepcopy(alts)
    for ii in range(len(measurement_alts)):
        #if have valid sampling height and altitude, create a measurement altitude
        if (pd.isnull(sampling_heights[ii]) == False) & (pd.isnull(alts[ii]) == False):
            measurement_alts[ii] = sampling_heights[ii] + alts[ii]
    
    invalid_inds = np.empty(0, dtype=np.uint32)
    for ii in range(len(measurement_alts)):
    
        #above high altitude limit?
        if measurement_alts[ii] >= high_altitude_limit:
            #is it last index? 
            if ii == (len(measurement_alts)-1):
                invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
            else:
                invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))
                
    #update relevant invalid inds with qa codes 
    if len(invalid_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('High Altitude - Metadata Altitude')
        for inv in invalid_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag
        
    return data 

###------------------------------------------------------------------------------------###

#Check for high altitude stations by standardised network provided 'terrain' metadata
#if terrain is classified as 'mountain', then the station is classed as high altitude

def high_altitude_classification_by_standardised_terrain_metadata(metadata,data):

    terrains = metadata['standardised_network_provided_terrain']
    update_metadata_stamp = metadata['meta_update_stamp']

    invalid_inds = np.empty(0, dtype=np.uint32)
    for ii in range(len(terrains)):

        #classed as 'mountain'? 
        if terrains[ii] == 'mountain':
            #is it last index? 
            if ii == (len(terrains)-1):
                invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
            else:
                invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))
     
    #update relevant invalid inds with qa codes 
    if len(invalid_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('High Altitude - Metadata Derived')
        for inv in invalid_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag
                  
    return data

###------------------------------------------------------------------------------------###

#Check for high altitude stations using ETOPO1 digital elevation model gridded data
#check is done by adding ETOPO1 altitude + sampling height to produce a measurement height, and this is checked to see if it is >= 1500 metres (relative to sea level datum).
#if no sampling height is available, only ETOPO1 altitude is used. 

def high_altitude_classification_by_ETOPO1(metadata,data):

    high_altitude_limit = 1500 #1500 metres relative to sea level datum

    ETOPO1_altitudes = metadata['ETOPO1_altitude']
    sampling_heights = metadata['sampling_height']
    update_metadata_stamp = metadata['meta_update_stamp']
    
    measurement_alts = copy.deepcopy(ETOPO1_altitudes)
    for ii in range(len(measurement_alts)):
        #if have valid sampling height and altitude, create a measurement altitude
        if (pd.isnull(sampling_heights[ii]) == False) & (pd.isnull(alts[ii]) == False):
            measurement_alts[ii] = sampling_heights[ii] + ETOPO1_altitudes[ii]
    
    invalid_inds = np.empty(0, dtype=np.uint32)
    for ii in range(len(measurement_alts)):
    
        #above high altitude limit?
        if measurement_alts[ii] >= high_altitude_limit:
            #is it last index? 
            if ii == (len(measurement_alts)-1):
                invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
            else:
                invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))
                
    #update relevant invalid inds with qa codes 
    if len(invalid_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('High Altitude - ETOPO1')
        for inv in invalid_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag
        
    return data 

###------------------------------------------------------------------------------------###

#Check for high altitude stations using the European Soil Data Centre Iwahashi Global Landform Classification gridded product

def high_altitude_classification_by_Iwahashi(metadata,data):

    Iwahashi_classifications = metadata['ESDAC_Iwahashi_landform_classification']
    update_metadata_stamp = metadata['meta_update_stamp']

    invalid_inds = np.empty(0, dtype=np.uint32)
    
    #for ii in range(len(Iwahashi_classifications)):
        
        #if Iwahashi_classifications[ii] == '':
            #is it last index? 
        #    if ii == (len(Iwahashi_classifications)-1):
        #        invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
        #    else:
        #        invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))
                
    #update relevant invalid inds with qa codes 
    if len(invalid_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('High Altitude - Iwahashi Global Landform Classification')
        for inv in invalid_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag
    

    return data

###------------------------------------------------------------------------------------###

#Check for high altitude stations using the European Soil Data Centre Meybeck Global Landform Classification gridded product

def high_altitude_classification_by_Meybeck(metadata,data):

    Meybeck_classifications = metadata['ESDAC_Meybeck_landform_classification']
    update_metadata_stamp = metadata['meta_update_stamp']

    invalid_inds = np.empty(0, dtype=np.uint32)
    
    #for ii in range(len(Meybeck_classifications)):
        
        #if Meybeck_classifications[ii] == '':
            #is it last index? 
        #    if ii == (len(Meybeck_classifications)-1):
        #        invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
        #    else:
        #        invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))
          

    #update relevant invalid inds with qa codes 
    if len(invalid_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('High Altitude - Meybeck Global Landform Classification')
        for inv in invalid_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag

    return data

###------------------------------------------------------------------------------------###

#Check for stations near coast by standardised network provided 'terrain' metadata
#if terrain is classified as 'coastal', then the station is classed as near coast

def near_coast_classification_by_standardised_terrain_metadata(metadata,data):

    terrains = metadata['standardised_network_provided_terrain']
    update_metadata_stamp = metadata['meta_update_stamp']

    invalid_inds = np.empty(0, dtype=np.uint32)
    for ii in range(len(terrains)):

        #classed as 'coastal'? 
        if terrains[ii] == 'coastal':
            #is it last index? 
            if ii == (len(terrains)-1):
                invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
            else:
                invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))
     
    #update relevant invalid inds with qa codes 
    if len(invalid_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Near Coast - Metadata Derived')
        for inv in invalid_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag

    return data
    
###------------------------------------------------------------------------------------###

#Check for stations near coast using the NASA Goddard Space Flight Center (GSFC) Ocean Color Group proximity to coast gridded dataset
#Negative distances represent locations over land (including land-locked bodies of water), while positive distances represent the ocean. 
#There is an uncertainty of up to 1 km in the computed distance at any given point.
#if the absolute proximity to the coast is <50 km, then a station is classed as near coast

def near_coast_classification_by_GSFC(metadata,data):

    GSFC_coastal_proximity = metadata['GSFC_coastline_proximity']
    update_metadata_stamp = metadata['meta_update_stamp']

    invalid_inds = np.empty(0, dtype=np.uint32)
    for ii in range(len(GSFC_coastal_proximity)):

        #absolute coastal proximity < 50m?
        if np.abs(GSFC_coastal_proximity[ii]) < 50:
            #is it last index? 
            if ii == (len(GSFC_coastal_proximity)-1):
                invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
            else:
                invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))
     
    #update relevant invalid inds with qa codes 
    if len(invalid_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Near Coast - GSFC')
        for inv in invalid_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag

    return data

###------------------------------------------------------------------------------------###

#Module that splits station into 'urban', 'rural' and 'unclassified' categories, derived from standardised network provided metadata, by lenient and strict definitions. 

#Methodology is as follows:
#Priority classification is "standardised_network_provided_measurement_scale" (gives information on the spatial representativity of measurements)
#Second priority classifications are "standardised_network_provided_area_classification" and "standardised_network_provided_station_classification" (gives information on the dominant type of air measured by a station, and type of area a measurement station is situated in)

#If measurement scale is provided, the second priority classifications are not used.
#If no categorisation can be made using the priority or second priority classifications, the station is unclassified.

#Lenient check definitions:
#1.
#standardised_network_provided_measurement_scale:      urban: ['micro', 'middle', 'neighbourhood', 'city'],                                     rural: ['regional']
#2.
#standardised_network_provided_area_classification:    urban: ['point_source']                                                                  rural: ['background']
#OR
#standardised_network_provided_station_classification: urban: ['urban']                                                                         rural: ['rural']

#Strict check definitions:
#1.
#standardised_network_provided_measurement_scale:      urban: ['micro', 'middle', 'neighbourhood', 'city'],                                     rural: ['regional']
#2.
#standardised_network_provided_area_classification:    urban: ['point_source']                                                                  rural: ['background']
#OR
#standardised_network_provided_station_classification: urban: ['rural-near_city', 'rural-regional', 'urban', 'urban-centre', 'urban-suburban'], rural: ['rural-remote']                                     rural: ['rural']

def rural_urban_classification_by_standardised_metadata(metadata,data):
    
    area_classifications = metadata['standardised_network_provided_area_classification']
    station_classifications = metadata['standardised_network_provided_station_classification']
    measurement_scales = metadata['standardised_network_provided_measurement_scale']
    update_metadata_stamp = metadata['meta_update_stamp']
    
    print area_classifications
    print station_classifications
    print measurement_scales
    
    rural_lenient_inds = np.empty(0, dtype=np.uint32)
    urban_lenient_inds = np.empty(0, dtype=np.uint32)
    unclassified_lenient_inds = np.empty(0, dtype=np.uint32)
    rural_strict_inds = np.empty(0, dtype=np.uint32)
    urban_strict_inds = np.empty(0, dtype=np.uint32)
    unclassified_strict_inds = np.empty(0, dtype=np.uint32)
    
    for ii in range(len(area_classifications)):
        
        #priority classification - "standardised_network_provided_measurement_scale"
        #rural?
        if measurement_scales[ii] in ['regional']:
            #is it last index? 
            if ii == (len(area_classifications)-1):
                rural_lenient_inds = np.append(rural_lenient_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
            else:
                rural_lenient_inds = np.append(rural_lenient_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))     
            rural_strict_inds = copy.deepcopy(rural_lenient_inds)
            
        #urban?
        elif measurement_scales[ii] in ['micro', 'middle', 'neighbourhood', 'city']:
            #is it last index? 
            if ii == (len(area_classifications)-1):
                urban_lenient_inds = np.append(urban_lenient_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
            else:
                urban_lenient_inds = np.append(urban_lenient_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))     
            urban_strict_inds = copy.deepcopy(urban_lenient_inds)
          
        #no standardised_network_provided_measurement_scale - use secondary classifications
        else:
            #lenient check
            #--------------------------------------------------
            #rural?
            if ('background' in area_classifications[ii]) & ('rural' in station_classifications[ii]):
                #is it last index? 
                if ii == (len(area_classifications)-1):
                    rural_lenient_inds = np.append(rural_lenient_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
                else:
                    rural_lenient_inds = np.append(rural_lenient_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))     
            #urban?
            elif ('point_source' in area_classifications[ii]) or ('urban' in station_classifications[ii]):
                #is it last index? 
                if ii == (len(area_classifications)-1):
                    urban_lenient_inds = np.append(urban_lenient_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
                else:
                    urban_lenient_inds = np.append(urban_lenient_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))     
            #unclassified?
            else:
                #is it last index? 
                if ii == (len(area_classifications)-1):
                    unclassified_lenient_inds = np.append(unclassified_lenient_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
                else:
                    unclassified_lenient_inds = np.append(unclassified_lenient_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))     
            
            #strict check
            #--------------------------------------------------
            #rural?
            if ('background' in area_classifications[ii]) & (station_classifications[ii] in ['rural-remote']):
                #is it last index? 
                if ii == (len(area_classifications)-1):
                    rural_strict_inds = np.append(rural_strict_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
                else:
                    rural_strict_inds = np.append(rural_strict_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))     
            #urban?
            elif ('point_source' in area_classifications[ii]) or (station_classifications[ii] in ['rural-near_city', 'rural-regional', 'urban', 'urban-centre', 'urban-suburban']):
                #is it last index? 
                if ii == (len(area_classifications)-1):
                    urban_strict_inds = np.append(urban_strict_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
                else:
                    urban_strict_inds = np.append(urban_strict_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))     
            #unclassified?
            else:
                #is it last index? 
                if ii == (len(area_classifications)-1):
                    unclassified_strict_inds = np.append(unclassified_strict_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
                else:
                    unclassified_strict_inds = np.append(unclassified_strict_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))     
            
                
    #update relevant invalid inds with qa codes 
    if len(rural_lenient_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Rural Station - Lenient Metadata Derived')
        for inv in rural_lenient_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag
            
    if len(urban_lenient_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Urban Station - Lenient Metadata Derived')
        for inv in urban_lenient_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag
            
    if len(unclassified_lenient_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Unclassified Station - Lenient Metadata Derived')
        for inv in unclassified_lenient_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag
            
    if len(rural_strict_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Rural Station - Strict Metadata Derived')
        for inv in rural_strict_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag
            
    if len(urban_strict_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Urban Station - Strict Metadata Derived')
        for inv in urban_strict_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag
            
    if len(unclassified_strict_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Unclassified Station - Strict Metadata Derived')
        for inv in unclassified_strict_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag
    
    return data
    
###------------------------------------------------------------------------------------###

#Module that splits station into 'urban' and 'rural' categories, derived from University of Maryland Baltimore County (UMBC) ANTHROME gridded classifications, describing the anthropogenic land use.

def rural_urban_classification_by_anthrome(metadata,data):

    anthrome_classifications = metadata['UMBC_anthrome_classification']
    update_metadata_stamp = metadata['meta_update_stamp']

    rural_anthrome_inds = np.empty(0, dtype=np.uint32)
    urban_anthrome_inds = np.empty(0, dtype=np.uint32)

    #for ii in range(len(anthrome_classifications)):
        
        #if anthrome_classifications[ii] == '':
            #is it last index? 
        #    if ii == (len(anthrome_classifications)-1):
        #        invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
        #    else:
        #        invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))
          

    #update relevant invalid inds with qa codes 
    if len(rural_anthrome_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Rural Station - Anthrome')
        for inv in rural_anthrome_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag

    #update relevant invalid inds with qa codes 
    if len(urban_anthrome_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Urban Station - Anthrome')
        for inv in urban_anthrome_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag

###------------------------------------------------------------------------------------###

#Module that splits station into 'urban', 'rural' and 'unclassified' categories, following definitions by the Tropospheric Ozone Assessment Report (TOAR).

def rural_urban_classification_by_TOAR(metadata,data):

    nighttime_lights = metadata['NOAA-DMSP-OLS_v4_nighttime_stable_lights']
    update_metadata_stamp = metadata['meta_update_stamp']

    rural_TOAR_inds = np.empty(0, dtype=np.uint32)
    urban_TOAR_inds = np.empty(0, dtype=np.uint32)
    unclassifed_TOAR_inds = np.empty(0, dtype=np.uint32)

    #for ii in range(len(nighttime_lights)):
        
        #if nighttime_lights[ii] == '':
            #is it last index? 
        #    if ii == (len(nighttime_lights)-1):
        #        invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
        #    else:
        #        invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))
          

    #update relevant invalid inds with qa codes 
    if len(rural_TOAR_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Rural Station - TOAR')
        for inv in rural_TOAR_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag

    #update relevant invalid inds with qa codes 
    if len(urban_TOAR_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Urban Station - TOAR')
        for inv in urban_TOAR_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag
            
    #update relevant invalid inds with qa codes 
    if len(unclassified_TOAR_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Unclassified Station - TOAR')
        for inv in unclassified_TOAR_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag

###------------------------------------------------------------------------------------###

#Module that splits station into 'urban', 'rural' and 'unclassified' categories, following definitions by Joly and Peuch (2012)

def rural_urban_classification_by_Joly_Peuch(metadata,data):

    update_metadata_stamp = metadata['meta_update_stamp']

    rural_Joly_Peuch_inds = np.empty(0, dtype=np.uint32)
    unclassifed_Joly_Peuch_inds = np.empty(0, dtype=np.uint32)

    #for ii in range(len()):
        
        #if [ii] == '':
            #is it last index? 
        #    if ii == (len()-1):
        #        invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), len(data['time'])))
        #    else:
        #        invalid_inds = np.append(invalid_inds,np.arange(bisect.bisect_left(data['time'], update_metadata_stamp[ii]), bisect.bisect_left(data['time'], update_metadata_stamp[ii+1])))
          

    #update relevant invalid inds with qa codes 
    if len(rural_Joly_Peuch_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Rural Station - Joly-Peuch')
        for inv in rural_Joly_Peuch_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag
            
    #update relevant invalid inds with qa codes 
    if len(unclassified_Joly_Peuch_inds) > 0:
        #get relevant qa flag
        qa_flag = standardisation_modules.get_standard_qa_flag('Unclassified Station - Joly-Peuch')
        for inv in unclassified_Joly_Peuch_inds:
            data['qa'][inv] = data['qa'][inv] + qa_flag

###------------------------------------------------------------------------------------###
