#!/usr/bin/env python
# -*-coding:utf-8-*-
'''
 通用方法工具类
@author: 'wanggongzheng'
'''
import sys
import datetime
import time

import config
import math

def is_null_str(src_str):
    """判断字符串是否为缺省值"""
    null_str_list = [r'NULL', r'NONE', r'\N']
    if src_str.upper() in null_str_list :
        return True
    return False

def generate_sql(table_name, columns, conditions):
    '''
    构造SQL查询语句
    :param table_name:
    :param columns:
    :param conditions:
    :return:
    '''
    sql_list = []
    sql_list.append(' SELECT ')
    sql_list.append(', '.join(columns))
    sql_list.append(' FROM ')
    sql_list.append(table_name + ' ')
    condition_str = conditions.strip(" ")
    if condition_str != "" :
        sql_list.append(" WHERE " + condition_str)
    return ' '.join(sql_list)

def get_dataframe(hive_context, table_name, src_features, conditions):
    """执行spark sql获取dataframe"""
    sql_str = generate_sql(table_name, src_features, conditions)
    log_info(sql_str)
    data_frame = hive_context.sql(sql_str)
    return data_frame

def map_row_with_key(row, key_names, v_names):
    """将row映射为(key, value)格式，当key个数为1时，不用元祖包装"""
    key_values = [str(row[a]) for a in key_names]
    key_tuple_values = tuple(key_values)
    if(len(key_values) == 1):
        key_tuple_values = (key_values[0])
    feature_values = [row[a] for a in v_names]
    feature_str = tuple_to_strs(feature_values)
    return (key_tuple_values, feature_str)

def fill_default_None_strs(column_num, default_str=config.str_for_None, delimiter=config.delimiter):
    """产生column_num列用分隔符以及缺省值的表示的缺省特征，用于join时缺失值填充"""
    res_element_list = [default_str] * column_num
    return delimiter.join(res_element_list)

def stardard_None_str(src, default_str=config.str_for_None):
    """将NULL 或None等格式缺失统一转化为统一的缺省字符"""
    s_str = str(src)
    res_str = s_str.strip(" ")
    res_str = res_str.lower()
    if res_str == "null" or res_str == "none" :
        s_str = default_str
    return s_str

def tuple_to_strs(element, delimiter=config.delimiter):
    """将tuple或list转为分隔符分隔的字符串"""
    if type(element) == str or type(element) == unicode:
        return str(element)
    else:
        element_str_list = map(stardard_None_str, element)
        return delimiter.join(element_str_list)

def left_join_fill_none(ele, right_num, delimiter=config.delimiter,
                      default_str=config.str_for_None):
    """left join产出的value聚合为字符串值，如果右边缺失，则根据右边数据源的数据列数补充\N"""
    right_str = ""
    if ele[1][1] == None:
        right_str = fill_default_None_strs(right_num, default_str, delimiter)
    else :
        right_str = tuple_to_strs(ele[1][1], delimiter)
    left_str = tuple_to_strs(ele[1][0], delimiter)
    return (ele[0], left_str + delimiter + right_str)

def left_join_fill_none_strs(ele, right_num, delimiter=config.delimiter,
                      default_str=config.str_for_None):
    """left join产出的key和value聚合为字符串值，如果右边缺失，则根据右边数据源的数据列数补充\N"""
    key_str = tuple_to_strs(ele[0])
    (key, value_str) = left_join_fill_none(ele, right_num, delimiter, default_st)
    return key_str + delimiter + value_str

def date_to_ymd_tuple(job_date):
    """获取日期的年月份并以元组方式返回"""
    year = datetime.datetime.strftime(job_date, "%Y")
    month = datetime.datetime.strftime(job_date, "%m")
    day = datetime.datetime.strftime(job_date, "%d")
    return (year, month, day)

def date_to_ymd_str(job_date):
    """获取日期的YYYYmmdd 20160401格式的字符串"""
    year = datetime.datetime.strftime(job_date, "%Y")
    month = datetime.datetime.strftime(job_date, "%m")
    day = datetime.datetime.strftime(job_date, "%d")
    ymd = year + month + day
    return ymd

def get_delta_date(job_date, delta):
    """获取job_date相隔delta的日期"""
    deltaTime = datetime.timedelta(days=delta)
    target_date = job_date + deltaTime
    return target_date

def get_near_days(job_date, from_delta, to_delta):
    """获取job_date相隔from_delta到相隔to_delta日期列表，左闭右开"""
    near_days =[]
    for i in range(from_delta, to_delta):
        c_date = job_date + datetime.timedelta(days=i)
        c_date_str = datetime.datetime.strftime(c_date, "%Y%m%d")
        near_days.append(c_date_str)
    return near_days

def get_day_delta(day1, day2, day_format ="%Y-%m-%d"):
    """获取两个日期（字符串形式，例如2016-12-01)之间的间隔天数"""
    day1_date = datetime.datetime.strptime(day1,day_format)
    day2_date = datetime.datetime.strptime(day2,day_format)
    return (day2_date - day1_date).days

def log_info(msg):
    """简单的日志包装，提供时间记录，如果复杂日志格式需求的话，可以自行替换"""
    msg = str(msg)
    print '['  + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) + ']:::' + msg

def log_fatal(msg):
    """输出错误级别日志,提供特定格式、醒目的前缀，便于后续查找错误信息 """
    msg_str = str(msg)
    log_info(config.error_prefix + msg_str)

def log_warn(msg):
    """输出警告级别日志，需关注，但不影响数据的正确性 """
    msg_str = str(msg)
    log_info(config.warn_prefix + msg_str)

def save_rdd_to_hdfs(sc, res_rdd, job_date, hdfs_path_prefix, res_name = "", file_count= config.output_hdfs_file_cnt):
    """将rdd按照时间分区的路径存储到hdfs上"""
    (year, month, day) = date_to_ymd_tuple(job_date)
    path = hdfs_path_prefix
    path += "/" + year + "/" + month + "/" + day
    log_info(res_name + " output path=" + path)
    res_rdd.coalesce(file_count) \
           .saveAsTextFile(path)

def rad(d):
    return (math.pi * d ) / 180.0

def sphereDistance(lat1, lng1, lat2, lng2):
    """输入为经纬度，计算两个点之间球面距离，单位为米"""
    EARTH_RADIUS = 6378.137
    radLat1 = rad(lat1)
    radLat2 = rad(lat2)
    a = radLat1 - radLat2
    b = rad(lng1) - rad(lng2)
    s = 2 * math.asin(math.sqrt(math.pow(math.sin(a / 2), 2)
        + math.cos(radLat1) * math.cos(radLat2) * math.pow(math.sin(b / 2), 2)))
    s = round(s * EARTH_RADIUS * 1000)
    return abs(s)

def map_to_libsvm(label, res_feas):
    """将特征数组以及label生成libsvm格式，label为label值，res_fea为特征数组"""
    res_str = str(label)
    for (i,value) in enumerate(res_feas):
	value_str = str(value)
	if value_str == str(config.str_for_None):
		value_str = config.missing_value_libsvm
        res_str += " " + str(i+1) + ":" + str(value_str)
    return res_str

def map_arr_to_libsvm(label_index, label_feas_arr):
    """包含了label的特征数组生成为libsvm格式，label_index为label在数组的位置，label_feas_arr为label + 特征的数组"""
    label = label_feas_arr[label_index]
    res_fea = label_feas_arr[0:label_index] + label_feas_arr[label_index+1:len(label_feas_arr)]
    return map_to_libsvm(label, res_fea)
