# ******************************************************
## Revision "$LastChangedDate: 2013-12-16 12:36:54 +0100 (Mon, 16 Dec 2013) $"
## Date "$LastChangedRevision: 426 $"
## Author "$LastChangedBy: arthurbeusen $"
## URL "$HeadURL: https://pbl.sliksvn.com/globalnutrients/generalcode/trunk/aggregate.py $"
# ******************************************************

from error import *
import sys
                      
def aggregate_grid(grid_ids,grid_val,dict,item,method=1,weighing=None):
    '''
    grid_ids is ascraster object with id's for each cell
    grid_val is ascraster object with values for each cell
    If method == 1: Summation
    If method == 2: Average
    If method == 3: Weighing summation with raster "weighing"
    If method == 4: Weighing Average with raster "weighing"
    '''
    lweighing = (method == 3 or method == 4)
    
    # Check input
    if (lweighing):
        if (weighing == None):
            # The function call is not correct
            raise MyError("AGGREGATE_GRID: Error in function call. Method 3 or 4 needs a weighing grid.")   
    
    dict_out = {}
    if (lweighing): dict_weigh={}

    if (method == 2):
        dict_count = {}
        #dict_count["Total"] = 0
    try:
        # Check length of the two lists:
        if (grid_ids.length != grid_val.length):
            raise MyError("AGGREGATE_GRID: Average is not possible on two grids of different length.",\
                           "Length of first list: "+str(grid_ids.length),\
                           "Length of second list: "+str(grid_val.length))

        if (lweighing):
            if (grid_ids.length != weighing.length):
                raise MyError("AGGREGATE_GRID: Length of weighing map is not correct.",\
                              "Length of value list: "+str(grid_ids.length),\
                              "Length of weighing list: "+str(weighing.length))
            nodata_value_weighing = weighing.nodata_value
                           
        nodata_value_ids = grid_ids.nodata_value
        nodata_value_val = grid_val.nodata_value
        for i in range(0,grid_ids.length):
            ids = grid_ids.values[i]
            if ids == nodata_value_ids:
                continue
            # Make from ids an integer.
            try:
                ids = int(ids)
            except ValueError:
                pass
            val = grid_val.values[i]
            if (val == nodata_value_val):
                continue
            if (lweighing):
                weigh = weighing.values[i]
                if (weigh == nodata_value_weighing):
                    if (val == 0.0):
                        # In this case it does not matter.
                        weigh = 0.0
                    else:
                        print "Weighing map has nodata values on essential places."
                        raise MyError("Weighing map is not correct. There are nodata values on essential places.")
                if (weigh < 0.0):
                    print "Weighing map has negative values on essential places."
                    raise MyError("Weighing map is not correct. There are negative values on essential places.")

            key = str(ids)
            value = float(val)
            try:
                if (method == 1 or method == 2):
                    dict_out[key] += value
                if (method == 2): dict_count[key] += 1
                if (lweighing): 
                    dict_out[key] += value * weigh
                    if (method == 4): dict_weigh[key] += weigh
            except KeyError:
                # Make a new entry in dict_out
                if (method == 1 or method == 2):
                    dict_out[key] = value
                if (method == 2): dict_count[key] = 1
                if (lweighing): 
                    dict_out[key] = value * weigh
                    if (method == 4): dict_weigh[key] = weigh

            
        if (method == 2):
            # Calculate average:
            for key in dict_out.keys():
                if (dict_count[key] > 0):
                    dict_out[key] /= dict_count[key]
        elif (method == 4):
            # Weighed average
            for key in dict_out.keys():
                if (dict_weigh[key] > 0):
                    dict_out[key] /= dict_weigh[key]
            
        for key in dict.keys():
            try:
                setattr(dict[key],str(item),dict_out[str(key)])
            except KeyError:
                pass

    except MyError,val:
        val.write()
        raise MyError()       
    except:
        raise MyError("AGGREGATE_GRID: Something goes wrong with error type: " + str(sys.exc_type),\
                      "ERROR in AGGREGATE_GRID and item " + str(item))
