#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon May 20 15:19:02 2019

@author: Marc.Schwaerzel
"""
import sys
import geopandas as gpd
import numpy as np
import xarray as xr

def make_tri_zh(coord_xmin, coord_ymin, dx, dy, shift, albedo, path, name, save_path):
    '''
    This functions calls all the function necessary to create the input trianfle (NetCDF) file
    '''
    shape_zh = extract_from_coords(unpack_shape(path), coord_xmin-shift, coord_xmin+dx+shift, coord_ymin-shift, coord_ymin+dy+shift);
    make_verti_tri_1(shape_zh, name=name, save_path=save_path,min_x=coord_xmin,min_y=coord_ymin, normalize=True, normalize_xy_only=True, alb=albedo)
    return 1

def unpack_shape(path):
    '''
    This functions unpacks the shape file
    '''
    shape = gpd.read_file(path)
    return shape

def extract_from_coords(shape, xmin, xmax,ymin,ymax):
    '''
    This functions extracts the buildings havin their centroid in the defined box
    '''
    array = []
    geom = [i for i in shape.geometry]
    height = shape.HEIGHT
    
    for i in shape.index:
        x,y = geom[i].exterior.coords.xy
        x = x.tolist()
        y = y.tolist()
        
        cx, cy = geom[i].centroid.coords.xy
        cx = cx[0]
        cy = cy[0]
        if xmin<cx<xmax and ymin<cy<ymax:
            array.append([i, x, y, height[i], cx, cy])
    return array

def make_verti_tri_1(shape, name="tri_zh", save_path="./data/triangles/", min_x=-1, min_y=-1, normalize=False, normalize_xy_only=False, alb=[.1,.1,.1,.1]):
    '''
    This functions makes the triangles out of the shape file
    '''
    ## make vertices ##
    vertices = []
    for ix in range(len(shape)):
        for iix in range(len(shape[ix][1])):
            x = np.round(shape[ix][1][iix],2)
            y = np.round(shape[ix][2][iix],2)
            z = np.round(shape[ix][3],2)
            cx = np.round(shape[ix][4],2)
            cy = np.round(shape[ix][5],2)
            if [x,y,z] in vertices:
                pass
            else:
                vertices.append([x,y,z])
            z0 = 0.    
            if [x,y,z0] in vertices:
                pass
            else:
                vertices.append([x,y,z0])
        if [cx, cy, z] in vertices:
            pass
        else:
            vertices.append([cx,cy,z])
                
    vertices = np.array(vertices)
    
    ## make triangles ##    
    index = np.arange(0,len(shape))
    shape_nr = []                 
    triangle_list = []     
    properties_list_ix = [] 
    for ix in range(len(index)):
        shape_nr.append(shape[ix][0])
        x1 = np.round(shape[ix][1],2)
        y1 = np.round(shape[ix][2],2)
        h1 = np.round(shape[ix][3],2)
        cx1 = np.round(shape[ix][4],2)
        cy1 = np.round(shape[ix][5],2)
        for px in range(len(x1)):
            xx = np.round(x1[px],2)
            yy = np.round(y1[px],2)
            if len(x1)-1!=px: # if we are at the last element of the shape
                xx1 = np.round(x1[px+1],2)
                yy1 = np.round(y1[px+1],2) 
            else:
                xx1 = np.round(x1[0],2)
                yy1 = np.round(y1[0],2) 
                
            # roof triangle
            tri_roof = [int(np.where((vertices[:,0]==xx) & (vertices[:,1]==yy) & (vertices[:,2]==h1))[0]),
                         int(np.where((vertices[:,0]==xx1) & (vertices[:,1]==yy1) & (vertices[:,2]==h1))[0]),
                         int(np.where((vertices[:,0]==cx1) & (vertices[:,1]==cy1) & (vertices[:,2]==h1))[0])]
            properties_list_ix.append(0.)
            
            # wall triangles
            tri_wall1 = [int(np.where((vertices[:,0]==xx) & (vertices[:,1]==yy) & (vertices[:,2]==h1))[0]),
                          int(np.where((vertices[:,0]==xx1) & (vertices[:,1]==yy1) & (vertices[:,2]==h1))[0]),
                          int(np.where((vertices[:,0]==xx) & (vertices[:,1]==yy) & (vertices[:,2]==0.))[0])]
            properties_list_ix.append(1)
            tri_wall2 = [int(np.where((vertices[:,0]==xx) & (vertices[:,1]==yy) & (vertices[:,2]==0.))[0]),
                          int(np.where((vertices[:,0]==xx1) & (vertices[:,1]==yy1) & (vertices[:,2]==h1))[0]),
                          int(np.where((vertices[:,0]==xx1) & (vertices[:,1]==yy1) & (vertices[:,2]==0.))[0])]
            properties_list_ix.append(1)
            
            # append to the triangle list
            triangle_list.append(tri_roof)
            triangle_list.append(tri_wall1)
            triangle_list.append(tri_wall2)  
    
    # define triangle vertices from 0 - 1 values
    if normalize:
        if min_x == -1:
            name = "%s_norm_plot"%name
            max_x = vertices[:,0].max()
            max_y = vertices[:,1].max()
            miin_x = vertices[:,0].min()
            miin_y = vertices[:,1].min()
            max_z = vertices[:,2].max()
            for ix in range(len(vertices[:,0])):
                vertices[ix,0] = (vertices[ix,0]-miin_x)/(max_x-miin_x)
                vertices[ix,1] = (vertices[ix,1]-miin_y)/(max_y-miin_y)
        else:
            print("normalize x,y")
            name = "%s_norm"%name
            print(vertices.shape)
            for ix in range(len(vertices[:,0])):
                vertices[ix,0] = vertices[ix,0]-min_x
                vertices[ix,1] = vertices[ix,1]-min_y
        if normalize_xy_only:
            name = "%s_xy"%name
            
        # normalize the altitude (0-1)
        else:
            print("normalize z")
            vertices[ix,2] = vertices[ix,2]/max_z
        
    # create and save NetCDF file
    triangles_list = np.array(triangle_list)    
    material_alb = np.array(alb)
#    material_alb = np.array([.25, .65, .2, .18])
    material_name = ["roof", "wall", "ground", "concrete/gravel"]
    tri_material = np.int64(np.array(properties_list_ix))
    tri_temperature = np.ones(len(tri_material))*273.15
    # create NetCDF arrays    
    vert = xr.DataArray(vertices, dims=('Nvert','Ndim'))
    tri = xr.DataArray(triangles_list, dims=('Ntriangles', 'Ncorner'))
    tri_material = xr.DataArray(tri_material, dims=['Ntriangles'])
    tri_temperature = xr.DataArray(tri_temperature, dims=['Ntriangles'])
    material_alb = xr.DataArray(material_alb,dims=['N_materials'])
    material_type = xr.DataArray(material_name,dims=['N_materials']) 
    # create NetCDF dataset
    nc_file = xr.Dataset({'vertices':vert,'triangles':tri,
                              'material_of_triangle':tri_material,
                              'material_albedo':material_alb,
                              'material_type':material_type,
                              'temperature_of_triangle':tri_temperature
                              })
    
    nc_file.to_netcdf("%s%s.nc"%(save_path,name) , format='NETCDF4')
    return nc_file

# run the triangle making from arguments
# input path / saving path / name / coord x min / coord y min / dx / dy / alebdo "roof" / "wall" / "ground" / "concrete/gravel"
path = "%s"%sys.argv[1]
save_path = "%s"%sys.argv[2]
name = "%s"%sys.argv[3]
coord_xmin = float(sys.argv[4])
coord_ymin = float(sys.argv[5])
dx = float(sys.argv[6])
dy = float(sys.argv[7])
shift = 0
albedo = [float(sys.argv[8]),float(sys.argv[9]),float(sys.argv[10]),float(sys.argv[11])]

make_tri_zh(coord_xmin, coord_ymin, dx, dy, shift, albedo, path, name, save_path)









