# Path: cmt/mapclient_qt.py
# def addToMap(self, eeobject, vis_params=None, name="", show=True):
#     '''Ads an EE object to the map'''
#         
#     # Flatten any lists to comma separated strings - needed for eeobject.getMapId() call below!
#     if vis_params:
#         vis_params = dict(vis_params)
#         for key in vis_params.keys():
#             item = vis_params.get(key)
#             if (isinstance(item, collections.Iterable) and (not isinstance(item, basestring))):
#                  vis_params[key] = ','.join([str(x) for x in item])
# 
#     def execute_thread(waiting_threads):
#         # get thread before starting
#         with self.thread_lock:
#             pass
#         result = eeobject.getMapId(vis_params)
#         for t in waiting_threads:
#             t.join()
#         with self.thread_lock:
#             self.executing_threads.pop(0)
#         return result
# 
#     with self.thread_lock:
#         self.executing_threads.append(cmt.util.miscUtilities.waitForEeResult(functools.partial(execute_thread, list(self.executing_threads)),
#                     lambda a : self.addOverlay(MakeTileManager(a), eeobject, name, show, vis_params)))
# 
# Path: cmt/util/miscUtilities.py
# def safe_get_info(ee_object, max_num_attempts=5):
#     '''Keep trying to call getInfo() on an Earth Engine object until it succeeds.'''
#     
#     # Do not try again if we get one of these exceptions
#     fail_messages = ['Too many pixels']
#     
#     num_attempts = 0
#     while True:
#         try:
#             return ee_object.getInfo()
#         except Exception as e:
#             # Rethrow the exception if it is not timeout related
#             for message in fail_messages:
#                 if message in str(e):
#                     raise e
#                     
#             print('Earth Engine Error: %s. Waiting 10s and then retrying.' % (e))
#             time.sleep(10)
#             num_attempts += 1
#         if max_num_attempts and (num_attempts >= max_num_attempts):
#             raise Exception('safe_get_info failed to succeed after ' +str(num_attempts)+ ' attempts!')
# 
# def get_permanent_water_mask():
#     '''Returns the global permanent water mask'''
#     return ee.Image("MODIS/MOD44W/MOD44W_005_2000_02_24").select(['water_mask'], ['b1'])


import ee
import math
import modis_utilities
import ee_classifiers
import simple_modis_algorithms
from cmt.mapclient_qt import addToMap
from cmt.util.miscUtilities import safe_get_info, get_permanent_water_mask
    
    # Compute the water fraction: (land - b) / (land - water)
    landDiff  = averagePureLandLocal.subtract(composite_image)
    waterDiff = averageWaterLocal.subtract(composite_image)
    typeDiff  = averagePureLandLocal.subtract(averageWaterLocal)
    #water_vector   = (averageLandLocal.subtract(b)).divide(averageLandLocal.subtract(averageWaterLocal))
    landDist  = landDiff.expression("b('sur_refl_b01')*b('sur_refl_b01') + b('sur_refl_b02') *b('sur_refl_b02') + b('sur_refl_b06')*b('sur_refl_b06')").sqrt();
    waterDist = waterDiff.expression("b('sur_refl_b01')*b('sur_refl_b01') + b('sur_refl_b02') *b('sur_refl_b02') + b('sur_refl_b06')*b('sur_refl_b06')").sqrt();
    typeDist  = typeDiff.expression("b('sur_refl_b01')*b('sur_refl_b01') + b('sur_refl_b02') *b('sur_refl_b02') + b('sur_refl_b06')*b('sur_refl_b06')").sqrt();
       
    #waterOff = landDist.divide(waterDist.add(landDist)) 
    waterOff = landDist.divide(typeDist) # TODO: Improve this math, maybe full matrix treatment?

    # Set pure water to 1, pure land to 0
    waterOff = waterOff.subtract(pureLand.multiply(waterOff))
    waterOff = waterOff.add(pureWater.multiply(ee.Image(1.0).subtract(waterOff)))
    
    # TODO: Better way of filtering out low fraction pixels.
    waterOff = waterOff.multiply(waterOff)
    waterOff = waterOff.gt(0.6)
    
    #addToMap(fraction,       {'min': 0, 'max': 1},   'fraction', False)
    addToMap(pureWater,      {'min': 0, 'max': 1},   'pure water', False)
    addToMap(pureLand,       {'min': 0, 'max': 1},   'pure land', False)
    addToMap(pureWaterCount, {'min': 0, 'max': 100}, 'pure water count', False)
    addToMap(pureLandCount,  {'min': 0, 'max': 100}, 'pure land count', False)
    
    
    #addToMap(numNearbyLandPixels,  {'min': 0, 'max': 400, }, 'numNearbyLandPixels', False)
    #addToMap(meanNearbyLand,       {'min': 0, 'max': 3000, 'bands': ['sum', 'sum_1', 'sum_2']}, 'meanNearbyLand', False)

# Path: cmt/mapclient_qt.py
# def addToMap(self, eeobject, vis_params=None, name="", show=True):
#     '''Ads an EE object to the map'''
#         
#     # Flatten any lists to comma separated strings - needed for eeobject.getMapId() call below!
#     if vis_params:
#         vis_params = dict(vis_params)
#         for key in vis_params.keys():
#             item = vis_params.get(key)
#             if (isinstance(item, collections.Iterable) and (not isinstance(item, basestring))):
#                  vis_params[key] = ','.join([str(x) for x in item])
# 
#     def execute_thread(waiting_threads):
#         # get thread before starting
#         with self.thread_lock:
#             pass
#         result = eeobject.getMapId(vis_params)
#         for t in waiting_threads:
#             t.join()
#         with self.thread_lock:
#             self.executing_threads.pop(0)
#         return result
# 
#     with self.thread_lock:
#         self.executing_threads.append(cmt.util.miscUtilities.waitForEeResult(functools.partial(execute_thread, list(self.executing_threads)),
#                     lambda a : self.addOverlay(MakeTileManager(a), eeobject, name, show, vis_params)))
# 
# Path: cmt/util/miscUtilities.py
# def safe_get_info(ee_object, max_num_attempts=5):
#     '''Keep trying to call getInfo() on an Earth Engine object until it succeeds.'''
#     
#     # Do not try again if we get one of these exceptions
#     fail_messages = ['Too many pixels']
#     
#     num_attempts = 0
#     while True:
#         try:
#             return ee_object.getInfo()
#         except Exception as e:
#             # Rethrow the exception if it is not timeout related
#             for message in fail_messages:
#                 if message in str(e):
#                     raise e
#                     
#             print('Earth Engine Error: %s. Waiting 10s and then retrying.' % (e))
#             time.sleep(10)
#             num_attempts += 1
#         if max_num_attempts and (num_attempts >= max_num_attempts):
#             raise Exception('safe_get_info failed to succeed after ' +str(num_attempts)+ ' attempts!')
# 
# def get_permanent_water_mask():
#     '''Returns the global permanent water mask'''
#     return ee.Image("MODIS/MOD44W/MOD44W_005_2000_02_24").select(['water_mask'], ['b1'])


# Path: cmt/modis/dnns.py
import ee
import math
import modis_utilities
import ee_classifiers
import simple_modis_algorithms
from cmt.mapclient_qt import addToMap
from cmt.util.miscUtilities import safe_get_info, get_permanent_water_mask

    
    # Compute the water fraction: (land - b) / (land - water)
    landDiff  = averagePureLandLocal.subtract(composite_image)
    waterDiff = averageWaterLocal.subtract(composite_image)
    typeDiff  = averagePureLandLocal.subtract(averageWaterLocal)
    #water_vector   = (averageLandLocal.subtract(b)).divide(averageLandLocal.subtract(averageWaterLocal))
    landDist  = landDiff.expression("b('sur_refl_b01')*b('sur_refl_b01') + b('sur_refl_b02') *b('sur_refl_b02') + b('sur_refl_b06')*b('sur_refl_b06')").sqrt();
    waterDist = waterDiff.expression("b('sur_refl_b01')*b('sur_refl_b01') + b('sur_refl_b02') *b('sur_refl_b02') + b('sur_refl_b06')*b('sur_refl_b06')").sqrt();
    typeDist  = typeDiff.expression("b('sur_refl_b01')*b('sur_refl_b01') + b('sur_refl_b02') *b('sur_refl_b02') + b('sur_refl_b06')*b('sur_refl_b06')").sqrt();
       
    #waterOff = landDist.divide(waterDist.add(landDist)) 
    waterOff = landDist.divide(typeDist) # TODO: Improve this math, maybe full matrix treatment?

    # Set pure water to 1, pure land to 0
    waterOff = waterOff.subtract(pureLand.multiply(waterOff))
    waterOff = waterOff.add(pureWater.multiply(ee.Image(1.0).subtract(waterOff)))
    
    # TODO: Better way of filtering out low fraction pixels.
    waterOff = waterOff.multiply(waterOff)
    waterOff = waterOff.gt(0.6)
    
    #addToMap(fraction,       {'min': 0, 'max': 1},   'fraction', False)
    addToMap(pureWater,      {'min': 0, 'max': 1},   'pure water', False)
    addToMap(pureLand,       {'min': 0, 'max': 1},   'pure land', False)
    addToMap(pureWaterCount, {'min': 0, 'max': 100}, 'pure water count', False)
    addToMap(pureLandCount,  {'min': 0, 'max': 100}, 'pure land count', False)
    
    
    #addToMap(numNearbyLandPixels,  {'min': 0, 'max': 400, }, 'numNearbyLandPixels', False)
    #addToMap(meanNearbyLand,       {'min': 0, 'max': 3000, 'bands': ['sum', 'sum_1', 'sum_2']}, 'meanNearbyLand', False)

    addToMap(averageWaterImage,    {'min': 0, 'max': 3000, 'bands': ['constant', 'constant_1', 'constant_2']}, 'average water', False)