# coding:utf-8
__author__ = 'wx'
import datetime
import copy
from rest_framework.decorators import api_view
from rest_framework.response import Response
from django.db import transaction
from django.db.models import Count
from django.db import connection

import mis.models as models
import mis.config as config
import tools.utils as utils
import mis.dao.methods_book as methods_book
import mis.dao.methods_monopoly as methods_monopoly
import mis.dao.methods_for_leave as methods_for_leave
import mis.dao.methods_user as methods_user
from schedule.reader import dao as schedule_reader
import logging
logger = logging.getLogger(__name__)

@api_view(["POST"])
@transaction.atomic
def monopolize_teacher_time(request):
    """
    买断老师时间
    startDate -- startDate
    endDate -- endDate
    startTime -- startTime
    endTime -- endTime
    teacherId -- teacherId
    course -- course time
    school -- school
    duration -- duration
    weeks -- weeklist 0,1,2
    type -- 0 生成新表 1 增加买断学校
    :param request:
    :return:
    """
    params = request.DATA
    if len(params) == 0:
        params = request.QUERY_PARAMS
    request_type = int(params.get("type"))
    start_date = params.get("startDate")
    end_date = params.get("endDate")
    start_time = params.get("startTime")
    end_time = params.get("endTime")
    school = params.get("school")
    real_duration = int(params.get("duration", 1))
    li_week = params.getlist("weeks", [1])
    li_week = [int(week) for week in li_week]
    teacher = models.User.objects.get(id=params.get("teacherId"))
    course_time = params.get("course", 0)
    price = params.get('price')
    if not price:
        return Response(dict(success=False, msg="必须填写价格!"))
    if request_type == 0:
        sid = transaction.savepoint()
        # 占用ta表的老师时间
        ta_query = models.TeacherAvailable.objects.filter(teacher_id=teacher.id).\
            filter(is_deleted=False).\
            filter(schedule=config.Schedule.AVAILABLE).\
            filter(date_slot__range=(start_date, end_date)).\
            filter(time_slot__range=(start_time, end_time)).\
            filter(weekday__in=li_week).filter(time_type=config.TeacherAvailableType.FIX)

        ta_num = ta_query.update(schedule=config.Schedule.MONOPOLY, school_id=school)
        if ta_num == 0:
            logger.info("monopoly old fail")
            return Response(dict(success=False, msg="老师课表没有可用时间"))
        # 生成新可用时间
        create_num = 0
        start_date = utils.str_to_date(start_date)
        end_date = utils.str_to_date(end_date)
        start_time = datetime.datetime.strptime(start_time, '%H:%M')
        end_time = datetime.datetime.strptime(end_time, '%H:%M')
        while start_date <= end_date:
            start_time_in = copy.deepcopy(start_time)
            if start_date.weekday() not in li_week:
                start_date = start_date + datetime.timedelta(days=1)
                continue
            # 去掉买断时间课程限制
            # 判断买断的时间段内老师是否有课，有课程则返回失败
            # class_num = models.Classes.objects.filter(attendance=config.Attendance.NORMAL).\
            #     filter(is_deleted=False).\
            #     filter(teacher_id=teacher.id).\
            #     filter(start_time__range=(str(start_date) + " " + str(start_time.time()),
            #                               str(start_date) + " " + str(end_time.time()))).\
            #     count()
            # if class_num > 0:
            #     transaction.savepoint_rollback(sid)
            #     return Response(dict(success=False, msg="买断时间内老师有课"))

            while start_time_in <= end_time:
                # 增加老师的实际占用时间
                # 如果开始时间-结束时间 大于 老师休息时间，则最后一节课不拍
                if (end_time - start_time_in).seconds / 60 + 30 < int(course_time):
                    break
                s_d = utils.date_to_str(start_date)
                s_t = datetime.datetime.strftime(start_time_in, "%H:%M")

                dt_slot = s_d + " " + s_t
                # count = models.MonopolizeTeacherAvailable.objects.filter(is_deleted=False).\
                #     filter(teacher_id=teacher.id, date_time_slot=dt_slot).count()
                # if count > 0:
                #     continue
                r = models.MonopolizeTeacherAvailable.objects.get_or_create(teacher_id=teacher.id,
                                                                            date_slot=start_date,
                                                                            time_slot=s_t,
                                                                            date_time_slot=dt_slot,
                                                                            schedule=config.Schedule.AVAILABLE,
                                                                            weekday=start_date.weekday(),
                                                                            duration=real_duration,
                                                                            course_time=int(course_time),
                                                                            school_id=school)
                if r:
                    create_num += 1
                start_time_in = start_time_in + datetime.timedelta(minutes=real_duration)
            start_date = start_date + datetime.timedelta(days=1)
        if ta_num == 0:
            return Response(dict(success=False, msg="老师课表没有可用时间"))
        else:
            transaction.savepoint_commit(sid)
            logger.info("special monopoly %s did it. teacher is %s, create %s, old %s",
                        request.user.id, teacher.nickname, create_num, ta_num)
            # 此处买断成功添加买断信息
            buy_out_info = models.BuyOutInfo(teacher=teacher,
                                             handler=request.user,
                                             price=price,
                                             start_date=start_date,
                                             end_date=end_date,
                                             start_time=start_time,
                                             end_time=end_time,
                                             school_id=school)
            buy_out_info.save()
            # buy
            ta_query.filter(school_id=1)
            ids = ta_query.values('id').distinct()
            ids = [x.get('id') for x in ids]
            buy_out_info.time_slots = ids
            buy_out_info.save()
            return Response(dict(old_num=ta_num, new_num=create_num, success=True))
    else:

        # 普通买断
        ta_num = models.TeacherAvailable.objects.filter(teacher_id=teacher.id).\
            filter(is_deleted=False).\
            filter(schedule__in=[config.Schedule.AVAILABLE, config.Schedule.USED]).\
            filter(date_slot__range=(start_date, end_date)).\
            filter(time_slot__range=(start_time, end_time)).\
            filter(weekday__in=li_week).filter(time_type=config.TeacherAvailableType.FIX)
        # 添加-如果施放,必须释放买断统计信息表的数据
        if int(school) == 1:

            sql = """
                delete buy_out_info_time_slots from buy_out_info_time_slots
                left join teacher_available as ta on ta.id = buy_out_info_time_slots.teacheravailable_id
                where
                ta.date_slot >= %s
                and ta.date_slot <= %s
                and ta.time_slot >= %s
                and ta.time_slot <= %s
                and ta.school_id > 1
                and ta.schedule = 0
                and ta.teacher_id = %s
            """
            cur = connection.cursor()
            cur.execute(sql, [start_date, end_date, start_time, end_time, teacher.id])
        ta_count = ta_num.update(school_id=school)

        logger.info("normal monopoly %s did it. teacher is %s, create %s",
                    request.user.id, teacher.nickname, ta_num)
        if int(school) >= 1:
            # 保存买断信息
            buy_out_info = models.BuyOutInfo(teacher=teacher,
                                             handler=request.user,
                                             price=price,
                                             start_date=start_date,
                                             end_date=end_date,
                                             start_time=start_time,
                                             end_time=end_time,
                                             school_id=school)
            buy_out_info.save()
            # 注意为了防止多次买断,此处已经买断的就不能再记录了
            ta_num.filter(school_id=1)
            ids = ta_num.values('id').distinct()
            ids = [x.get('id') for x in ids]
            buy_out_info.time_slots = ids
            buy_out_info.save()
        return Response(dict(old_num=ta_count, new_num=ta_count, success=True))

@api_view(["POST"])
def del_monopolize_teacher_time(request):
    """
    恢复老师时间
    startDate -- startDate
    endDate -- endDate
    startTime -- startTime
    endTime -- endTime
    teacherId -- teacherId
    type -- 0 生成新表 1 增加买断学校
    :param request:
    :return:
    """
    params = request.DATA
    if len(params) == 0:
        params = request.QUERY_PARAMS
    start_date = params.get("startDate")
    end_date = params.get("endDate")
    start_time = params.get("startTime")
    end_time = params.get("endTime")
    teacher = models.User.objects.get(id=params.get("teacherId"))
    sid = transaction.savepoint()
    # 释放ta表的老师时间
    ta_num = models.TeacherAvailable.objects.filter(teacher_id=teacher.id).\
        filter(is_deleted=False).\
        filter(schedule=config.Schedule.MONOPOLY).\
        filter(date_slot__range=(start_date, end_date)).\
        filter(time_slot__range=(start_time, end_time)).\
        update(schedule=config.Schedule.AVAILABLE, school_id=1)
    # 删除mta表的老师时间
    del_num = models.MonopolizeTeacherAvailable.objects.filter(teacher_id=teacher.id).\
        filter(date_slot__range=(start_date, end_date)).\
        filter(time_slot__range=(start_time, end_time)).\
        filter(schedule=config.Schedule.AVAILABLE).\
        delete()

    # -如果施放,必须释放买断统计信息表的数据
    sql = """
        delete buy_out_info_time_slots from buy_out_info_time_slots
        left join teacher_available as ta on ta.id = buy_out_info_time_slots.teacheravailable_id
        where
        ta.date_slot >= %s
        and ta.date_slot <= %s
        and ta.time_slot >= %s
        and ta.time_slot <= %s
        and ta.schedule = 6
        and ta.teacher_id = %s
    """
    cur = connection.cursor()
    cur.execute(sql, [start_date, end_date, start_time, end_time, teacher.id])
    transaction.savepoint_commit(sid)
    logger.info("%s release teacher %s, release number %s, delete monopoly number %s",
                request.user.id, teacher, ta_num, del_num)
    return Response(dict(old_num=ta_num, new_num=del_num, success=True))

@api_view(["POST"])
def query_monopoly_schedule(request):
    """
    courseId -- course_pk
    startTime -- starttime
    endTime -- endTime
    startDate -- startdate
    endDate -- enddate
    teacher -- teacher
    week -- week
    page -- page
    :param request:
    :return:
    """
    params = request.DATA
    if len(params) == 0:
        params = request.QUERY_PARAMS
    course = params.get("courseId", None)
    min_time = params.get("startTime", "8:30")
    max_time = params.get("endTime", "21:30")
    start_date = params.get("startDate")
    end_date = params.get("endDate")
    teacher = params.get("teacher", None)
    week = params.get("week", 1)
    page = params.get("page", 1)
    interview = params.get('interview', None)  # 隔周选课
    week_list = params.get('weekList', None)  # 一周中周几选课
    if min_time.encode("utf-8") is '':
        min_time = "8:30"
    if max_time.encode("utf-8") is '':
        max_time = "21:30"
    if isinstance(page, unicode):
        page = int(page)
    cnt, data, li_date_group = methods_book.monopoly_query_book_teacher(start_time=start_date,
                                                                        end_time=end_date,
                                                                        course_pk=course,
                                                                        start_slot=min_time,
                                                                        end_slot=max_time,
                                                                        teacher=teacher,
                                                                        week=week,
                                                                        page=page,
                                                                        interview=interview,
                                                                        week_list=week_list)
    return Response(dict(total=cnt[0], res=data, group=li_date_group))

@api_view(["POST"])
def monopoly_book_classes(request):
    """
    排课
    uid -- userid
    courseId -- courseid
    teacher -- teacher
    week -- time
    date -date
    :param request:
    :return:
    """
    params = request.QUERY_PARAMS
    if not params:
        params = request.DATA
    course = params.get("courseId")
    uid = params.get("uid")
    teacher = params.get("teacher")
    li_group = eval(params.get("date"))
    time_slot = params.get("time")
    time_slot = time_slot.encode("utf-8").split(",")
    user = models.User.objects.get(id=uid)
    # li_group = methods_book.get_date_group(start_date, end_date, week)
    res = methods_monopoly.monopoly_create_classes(course=course, student=uid,
                                                   teacher=teacher, date_slots=li_group,
                                                   time_slots=time_slot)
    if res is True:
        # 获取学生的课表
        course = models.Course.objects.get(object_pk=course)
        teacher = models.User.objects.get(object_pk=teacher)
        li_classes = []
        count = 0
        for d in li_group:
            count += 1
            if isinstance(time_slot, list):
                time_slot = time_slot[0]
            li_classes.append(dict(startTime=d + " " + time_slot, teacher=teacher.nickname, course=course.name))
        logger.info("student " + str(uid) + " create classes " + str(count))
        return Response(dict(success=True, count=count, classesInfo=li_classes, uid=user.number))
    else:
        return Response(dict(success=False))

@api_view(["POST"])
def get_all_classes_can_ask_leave(request):
    """
    根据课表查询所以未上课的课程信息
    courseId -- course
    uid -- uid
    :param request:
    :return:
    """
    params = request.DATA
    if len(params) == 0:
        params = request.QUERY_PARAMS
    course = params.get("courseId")
    uid = params.get("uid")
    student = models.User.objects.get(id=uid)
    course = models.Course.objects.get(object_pk=course)
    now = datetime.datetime.now() + datetime.timedelta(minutes=120)
    # classes = models.Classes.objects.filter(student_id=student.id).\
    #     filter(course_id=course.id).\
    #     filter(is_deleted=False).\
    #     filter(attendance=config.Attendance.NORMAL).\
    #     filter(start_time__range=(now, now + datetime.timedelta(days=7)))
    classes = models.Classes.objects.filter(student_id=student.id).\
        filter(course_id=course.id).\
        filter(is_deleted=False).\
        filter(attendance=config.Attendance.NORMAL)

    li_res = []
    count = 0
    if len(classes) > 0:
        for c in classes:
            teacher = models.User.objects.get(id=c.teacher_id)
            count += 1
            li_res.append(dict(startTime=c.start_time.strftime('%Y-%m-%d %H:%M'),
                               endTime=c.end_time.strftime('%Y-%m-%d %H:%M'),
                               teacherName=teacher.nickname,
                               courseName=course.name,
                               startDate=(c.start_time + datetime.timedelta(days=1)).strftime('%Y/%m/%d'),
                               endDate=(c.start_time + datetime.timedelta(days=7)).strftime('%Y/%m/%d'),
                               defaultDate=(c.start_time + datetime.timedelta(days=1)).strftime('%Y-%m-%d'),
                               Id=c.id))
    if count > 0:
        return Response(dict(success=True, res=li_res))
    else:
        return Response(dict(success=True, res="", num=0))

@api_view(["POST"])
def monopoly_ask_for_leave_choice(request):
    """
    请假课程日期以后7天内任选老师或时间请假
    teacher_or_time  -- 1/0
    clazz -- clazz_id
    date_time_slot -- date_time_slot
    :param request:
    :return:
    """
    params = request.DATA
    if not params:
        params = request.QUERY_PARAMS
    teacher_or_time = params.get("tos", 1)
    clazz_id = params.get("classId", None)
    date_time_slot = params.get("dts", None)
    # 判断是否可以请假

    clazz = models.Classes.objects.get(id=clazz_id)
    if not methods_for_leave.vail_ask_leave_number(clazz_id, 7):
        logger.info("over max ask for leave time 7")
        return Response(dict(success=False, msg="超过了最大请假次数"))

    clazz = models.Classes.objects.get(id=clazz_id)
    date_start = clazz.start_time.date()
    if int(teacher_or_time) == 1:
        # teacher default
        date_end = date_start + datetime.timedelta(days=8)
        time_start = "17:30"
        time_end = "20:30"
        duration = clazz.end_time - clazz.start_time
        teacher = models.User.objects.get(id=clazz.teacher_id)
        duration_min = duration.seconds / 60
        if duration_min <= 30:
            t_available = models.TeacherAvailable.objects.filter(teacher_id=teacher.id)\
                .filter(schedule=config.Schedule.AVAILABLE)\
                .filter(date_slot__gte=date_start)\
                .filter(date_slot__lt=date_end)\
                .exclude(time_slot__range=(time_start, time_end))\
                .order_by("date_time_slot")
            li_res = [t.date_time_slot.strftime("%Y-%m-%d %H:%M") for t in t_available]
            return Response(dict(success=True, res=li_res, teacher=clazz.teacher_id,
                                 type="teacher", teacherName=teacher.nickname))
        else:
            if duration_min % 30 != 0:
                slot_num = duration_min / 30
            else:
                slot_num = duration_min / 30 - 1
            min = slot_num * 30
            time_start = (time_start.strptime("%H:%M") + datetime.timedelta(minutes=min)).strftime("%H:%M")
            time_end = (time_end.strptime("%H:%M") + datetime.timedelta(minutes=min)).strftime("%H:%M")
            t_available = models.TeacherAvailable.objects.filter(teacher_id=teacher.id)\
                .filter(schedule=config.Schedule.AVAILABLE)\
                .filter(date_slot__gte=date_start)\
                .filter(date_slot__lt=date_end)\
                .exclude(time_slot__range=(time_start, time_end))\
                .order_by("date_time_slot")
            li_res = [t.date_time_slot.strftime("%Y-%m-%d %H:%M") for t in t_available]
            # li_res = [t.date_time_slot for t in t_available]
            li_fin = []
            # query time slot's next time slot is available or not
            for k, v in enumerate(li_res):
                flag = True
                # 判断后N个时间点老师都有时间
                for i in range(1, slot_num + 1):
                    time_slot_i = utils.str_to_datetime(v, "%Y-%m-%d %H:%M") + datetime.timedelta(minutes=(i * 30))
                    try:
                        if li_res[k+i] != time_slot_i.strftime("%Y-%m-%d %H:%M"):
                            flag = False
                            continue
                    except:
                        flag = False
                        continue
                if flag is False:
                    continue
                li_fin.append(v)
            return Response(dict(success=True, res=li_fin, teacher=clazz.teacher_id, type="teacher", teacherName=teacher.nickname))
    else:
        # time slot default
        date_time = utils.str_to_datetime(date_time_slot, matter="%Y-%m-%d %H:%M")
        course = models.Course.objects.get(id=clazz.course_id)
        student = models.User.objects.get(id=clazz.student_id)

        tas = models.MonopolizeTeacherAvailable.objects.filter(is_deleted=False).\
            filter(date_time_slot=date_time).\
            filter(schedule=config.Schedule.AVAILABLE).\
            filter(course_time=course.duration).\
            filter(school_id=student.school_id)
        li_res = []
        for ta in tas:
            teacher = models.User.objects.get(id=ta.teacher_id)
            li_res.append(dict(id=teacher.id, name=teacher.nickname, rate=0))
        return Response(dict(res=li_res, success=True, type="time"))

@transaction.atomic
@api_view(["POST"])
def monopoly_change_schedule(request):
    """
    根据课程修改老师的可用时间和课程信息
    class -- 课程id
    teacher -- 老师id
    date_time_slot -- 日期时间组
    :param request:
    :return:
    """
    params = request.DATA
    if len(params) == 0:
        params = request.QUERY_PARAMS
    class_id = params.get("classId")
    teacher_id = params.get("teacher")
    date_time_slot = params.get("dts")
    clazz = models.Classes.objects.get(id=class_id)
    duration = clazz.end_time - clazz.start_time
    duration_min = duration.seconds / 60
    sid = transaction.savepoint()
    # 更改 classes表
    # 更改 teacher available 表
    ta_old = models.MonopolizeTeacherAvailable.objects.filter(teacher_id=clazz.teacher_id)\
        .filter(date_time_slot=clazz.start_time)\
        .filter(schedule=config.Schedule.USED)\
        .update(schedule=config.Schedule.AVAILABLE)
    ta_new = models.MonopolizeTeacherAvailable.objects.filter(teacher_id=teacher_id)\
        .filter(date_time_slot=date_time_slot)\
        .filter(schedule=config.Schedule.AVAILABLE)\
        .update(schedule=config.Schedule.USED)
    if ta_new + ta_old != 2:
        return Response(dict(success=False, msg="老师的时间已被占用,换个时间吧"))

    clazz.is_deleted = True
    clazz.attendance = config.Attendance.CANCEL
    clazz.save()
    end_time = utils.str_to_datetime(date_time_slot, "%Y-%m-%d %H:%M") + datetime.timedelta(minutes=duration_min)
    models.Classes.objects.get_or_create(title=clazz.title,
                                         class_type=clazz.class_type,
                                         start_time=date_time_slot,
                                         end_time=end_time,
                                         course=clazz.course,
                                         student=clazz.student,
                                         teacher_id=teacher_id,
                                         appointment_id=clazz.appointment_id)
    methods_for_leave.update_re_schedule(class_id)

    transaction.savepoint_commit(sid)
    logger.info("Success ask for leave and create new class")
    return Response(dict(success=True))

@api_view(["POST"])
def re_query_monopoly_schedule(request):
    """
    查询重排课表
    courseId -- course_pk
    startTime -- starttime
    endTime -- endTime
    startDate -- startdate
    endDate -- enddate
    teacher -- teacher
    week -- week
    page -- page
    :param request:
    :return:
    """
    params = request.DATA
    if len(params) == 0:
        params = request.QUERY_PARAMS
    uid = params.get("uid", None)
    course = params.get("courseId", None)
    min_time = params.get("startTime", "8:30")
    max_time = params.get("endTime", "21:30")
    teacher = params.get("teacher", None)
    week = params.get("week", 1)
    page = params.get("page", 1)
    if min_time.encode("utf-8") is '':
        min_time = "8:30"
    if max_time.encode("utf-8") is '':
        max_time = "21:30"
    if isinstance(page, unicode):
        page = int(page)
    cnt, data, li_date_group = methods_book.monopoly_re_query_book_teacher(course_pk=course,
                                                                           start_slot=min_time,
                                                                           end_slot=max_time,
                                                                           teacher=teacher,
                                                                           week=week,
                                                                           page=page,
                                                                           uid=uid)

    return Response(dict(total=cnt[0], res=data, group=li_date_group))

@api_view(["POST"])
@transaction.atomic
def re_schedule_classes(request):
    """
    重排课
    :param request:
    :return:
    """
    params = request.QUERY_PARAMS
    if not params:
        params = request.DATA
    course = params.get("courseId")
    uid = params.get("uid")
    teacher = params.get("teacher")
    li_group = eval(params.get("date"))
    time_slot = params.get("time")
    time_slot = time_slot.encode("utf-8").split(",")[0]

    user = models.User.objects.get(id=uid)
    teacher = models.User.objects.get(object_pk=teacher)
    course = models.Course.objects.get(object_pk=course)
    # TODO 判断重排次数
    sid = transaction.savepoint()
    # 课表删除
    classes_old = models.Classes.objects.filter(course_id=course.id).\
        filter(student_id=user.id).\
        filter(is_deleted=False).\
        filter(attendance=config.Attendance.NORMAL)

    class_demo = classes_old[0]

    li_old_date_time_group = []
    tt_old_num = 0
    for c in classes_old:
        li_old_date_time_group.append(c.start_time)
        # 释放老师时间
        t = models.MonopolizeTeacherAvailable.objects.filter(is_deleted=False).\
            filter(teacher_id=c.teacher_id).\
            filter(course_time=course.duration).\
            filter(date_time_slot=c.start_time).\
            filter(schedule=config.Schedule.USED).\
            update(schedule=config.Schedule.AVAILABLE)
        tt_old_num += t

    classes_old_num = classes_old.update(is_deleted=True, attendance=config.Attendance.CANCEL)

    # tt_old = models.MonopolizeTeacherAvailable.objects.filter(is_deleted=False).\
    #     filter(teacher_id=teacher.id).\
    #     filter(course_id=course.id).\
    #     filter(date_time_slot__in=li_old_date_time_group).\
    #     filter(schedule=config.Schedule.USED)
    # tt_old_num = tt_old.update(schedule=config.Schedule.AVAILABLE)
    # 课表生成
    classes_new_num = 0
    for d in li_group:
        start_time = utils.str_to_datetime(d + " " + time_slot, "%Y-%m-%d %H:%M")
        models.Classes.objects.create(title=class_demo.title,
                                      class_type=class_demo.class_type,
                                      start_time=start_time,
                                      end_time=start_time + datetime.timedelta(minutes=course.duration),
                                      course=course,
                                      student=user,
                                      teacher=teacher)
        classes_new_num += 1

    # 占用老师时间
    tt_new_num = models.MonopolizeTeacherAvailable.objects.filter(is_deleted=False).\
        filter(teacher_id=teacher.id).\
        filter(course_time=course.duration).\
        filter(date_slot__in=li_group).\
        filter(time_slot=time_slot).\
        filter(schedule=config.Schedule.AVAILABLE).\
        update(schedule=config.Schedule.USED)

    if classes_old_num == classes_new_num and tt_new_num == tt_old_num:
        # 增加重排次数
        rs = models.ReSchedule.objects.get(course_id=course.id, student_id=user.id)
        rs.re_book_times += 1
        rs.save()
        transaction.savepoint_commit(sid)
        return Response(dict(success=True))
    else:
        logger.info("ReSchedule fail, classes old is %s,classes new is %s, tt new is %s, tt old is ",
                    classes_old_num, classes_new_num, tt_new_num, tt_old_num)
        return Response(dict(success=False))

@api_view(['POST', 'GET'])
def get_class_notes(request):
    """
    rs获取class note
    partner -- partner
    uid -- uid
    :param request:
    :return:
    """
    logger.info("enter classnote")
    params = request.QUERY_PARAMS
    if not params:
        params = request.DATA
    partner = params.get("partner")
    uid = params.get("uid")
    logger.info(str(partner) + str(uid))
    school = models.School.objects.get(object_pk=partner)
    logger.info(str(school.id) + str(uid))
    student = models.User.objects.get(number=uid, school_id=school.id)
    classes = models.Classes.objects.filter(student_id=student.id).filter(is_deleted=False)
    re = []  # 返回的数据列表
    if len(classes) > 0:
        for clazz in classes:
            # 判断是否有classNote
            class_note = models.ClassNotes.objects.filter(is_deleted=False).\
                order_by('-create_time').\
                filter(clazz=clazz)
            if len(class_note) > 0:
                for note in class_note:
                    pronunciation = None
                    grammar = None
                    try:
                        pronunciation = models.NotesPronunciation.objects.filter(note=note.id).filter(is_deleted=False)\
                            .order_by('-create_time')
                        grammar = models.NotesGrammar.objects.filter(note=note.id).filter(is_deleted=False)\
                            .order_by('-create_time')
                    except:
                        pass
                    data = dict(id=note.id, create_time=note.create_time.strftime("%Y-%m-%d %H:%M"), suggestion=note.suggestion, clazz_id=note.clazz_id,
                                replay_id=note.replay_id, score=note.score,
                                writer=dict(id=note.writer_id, name=methods_user.get_user_by(note.writer_id).nickname))
                    data['pronunciation'] = []
                    if pronunciation:
                        for p in pronunciation:
                            data['pronunciation'].append(dict(note_id=p.note_id,
                                                              word=p.word,
                                                              phoneme_error=p.phoneme_error,
                                                              tips=p.tips))
                    data['grammar'] = []
                    if grammar:
                        for g in grammar:
                            data['grammar'].append(dict(note_id=g.note_id,
                                                        syntax_error=g.syntax_error,
                                                        correction=g.correction,
                                                        tips=g.tips))
                    re.append(data)
    return Response(dict(data=re, count=len(re), success=True))

@api_view(["POST"])
def leave_list_special(request):
    """
    请假课程日期以后7天内任选老师或时间请假
    teacher_or_time  -- 1/0
    clazz -- clazz_id
    date_time_slot -- date_time_slot
    :param request:
    :return:
    """
    params = request.DATA
    if not params:
        params = request.QUERY_PARAMS
    teacher_or_time = params.get("tos", 0)
    clazz_id = params.get("classId", None)
    # 判断是否可以请假
    # if not methods_for_leave.vail_ask_leave_number(clazz_id):
    #     return Response(dict(success=False, msg="超过了最大请假次数"))

    clazz = models.Classes.objects.get(id=clazz_id)
    if not methods_for_leave.vail_ask_leave_number(clazz_id, 2):
        logger.info("over max ask for leave time 2")
        return Response(dict(success=False, msg="超过了最大请假次数"))
    # student_id = clazz.student_id
    # course = models.Course.objects.get(id=clazz.course_id)
    # leave_num = methods_for_leave.get_max_leave_times(course.id, student_id, None)
    # if leave_num > 7:
    #     return Response(dict(success=False, msg="超过了最大请假次数"))

    clazz = models.Classes.objects.get(id=clazz_id)
    if int(teacher_or_time) == 1:
        pass
    else:
        # time slot default
        course = models.Course.objects.get(id=clazz.course_id)
        student = models.User.objects.get(id=clazz.student_id)

        tas = models.MonopolizeTeacherAvailable.objects.\
            filter(date_slot__in=['2015-07-18', '2015-07-25']).\
            filter(schedule=config.Schedule.AVAILABLE).\
            filter(course_time=course.duration).\
            filter(school_id=student.school_id)
        li_res = []
        for ta in tas:
            teacher = models.User.objects.get(id=ta.teacher_id)
            li_res.append(dict(id=teacher.id, name=teacher.nickname, rate=0,
                               start=ta.date_time_slot,
                               end=ta.date_time_slot + datetime.timedelta(minutes=25)))
        return Response(dict(res=li_res, success=True, type="time"))

@api_view(["GET"])
def get_buy_out_info(request):
    """
    获取买断信息,以机构分组
    :param request:
    :return:
    """
    query_set = models.TeacherAvailable.objects.exclude(school_id=1)\
        .filter(is_deleted=False,)
    query_set.query.group_by = ['school_id']
    query_set = query_set.annotate(Count('school_id'))
    entries = [{'school': {'id': str(x.school.id),
                           'name': x.school.name},
                'count': x.school_id__count} for x in query_set]
    return Response(dict(success=True, data=entries))

@api_view(["GET"])
def get_mono_teachers_school(request):
    """
    获取某个机构的买断老师
    :param request:
    :return:
    """
    school_id = request.GET.get('school_id', '')
    query_set = models.TeacherAvailable.objects\
        .filter(school_id=school_id)
    query_set.query.group_by = ['teacher_id']
    query_set = query_set.annotate(Count('teacher_id'))
    teachers = [{'teacher': {'name': x.teacher.first_name,
                             'id': x.teacher_id,
                             'price': schedule_reader.get_price_teacher_monopoly(teacher_id=x.teacher_id,
                                                                                school_id=school_id)},
                 'count': x.teacher_id__count} for x in query_set]
    return Response(dict(success=True, data=teachers))

@api_view(["GET"])
def save_supplement_monopoly_info(request):
    """
    保存某个机构买断某个老师的价格
    :param request:
    :return:
    """
    teacher_id = request.GET.get('teacher_id')
    school_id = request.GET.get('school_id')
    price = request.GET.get('price')

    if not teacher_id or not school_id or not price:
        return Response(dict(success=False, data=''))
    sid = transaction.savepoint()
    try:
        if models.BuyOutInfo.objects.filter(teacher_id=teacher_id,
                                            school_id=school_id).exists():
            buy_out_info = models.BuyOutInfo.objects.filter(teacher_id=teacher_id,
                                                            school_id=school_id)
            buy_out_info.update(price=price)
            transaction.savepoint_commit(sid=sid)
            return Response(dict(success=True, data=''))
        buy_out_info = models.BuyOutInfo(teacher_id=teacher_id,
                                         school_id=school_id,
                                         price=price,
                                         handler=request.user)
        buy_out_info.save()
        query_set = models.TeacherAvailable.objects.filter(teacher_id=teacher_id,
                                                           school_id=school_id,
                                                           is_deleted=False).values('id').distinct()
        ids = [x.get('id') for x in query_set]
        buy_out_info.time_slots = ids
        buy_out_info.save()
        transaction.savepoint_commit(sid=sid)
        return Response(dict(success=True, data=''))
    except:
        transaction.savepoint_rollback(sid=sid)
        return Response(dict(success=False, data=''))


# -*- coding: utf-8 -*-
"""
Noise Fitting Brownian Motion Data

Ryan Dwyer

2013-11-22

This document will implement John Marohn's Brownian motion noise
fitting routine in Python. The class ``BrownianMotionFitter`` implements the
fitting routine. The rest of the module consists of helper functions for
specific portions of the fitting procedure and data input / output.

Dependencies:

- numpy
- scipy
- matplotlib
- pint
- uncertainties
- h5py

"""

from __future__ import division
import os
import errno

import numpy as np
import scipy
import scipy.stats
import six
sp = scipy
from scipy.optimize import curve_fit
import matplotlib as mpl
# Backend should be set correctly here.
from uncertainties import correlated_values, ufloat
import h5py
import pint

u = pint.UnitRegistry()

k_B = u.boltzmann_constant

class Cantilever(object):
    """Implement a simple unit cantilever, and require all inputs."""

    k_B = k_B

    def __init__(self, f_c, k_c, Q):
        """Initialize the cantilever."""
        self.f_c = f_c
        self.k_c = k_c
        self.Q = Q

    # Properties of the cantilver
    @property
    def omega_c(self):
        """Return the angular resonance frequency of the cantilever."""
        return self.f_c * 2 * pi

    @property
    def Gamma_i(self):
        """Return the cantilever's intrinsic dissipation."""
        return (self.k_c / (self.omega_c * self.Q))

    def F_min(self, T, bandwidth=1*u.Hz):
        """Return the thermally limited minimum detectable
        force (pN).

        The optional bandwidth parameter allows determining
        a miniumun force over a broader or narrower bandwidth
        than 1 Hz."""
        return ((4 * self.k_B * self.Gamma_i * T * bandwidth) ** 0.5)

    # Representations of the cantilever
    def __str__(self):
        """Write out the cantilever as its most important parameters:
        resonance frequency, spring constant, quality factor and
        intrinsic friction."""
        return "f_c = {self.f_c}, k_c = {self.k_c}, Q = {self.Q}\
Gamma_i = {self.Gamma_i}".format(self=self)

    def __repr__(self):
        """Return a representation of the cantilever. Rounds the cantilever
        to 9 digits, so eval(repr(cantilever)) is not necessarily equal to
        cantilever."""
        return "Cantilever(f_c = {self.f_c}, k_c = {self.k_c}, \
Q = {self.Q})".format(self=self)

class BrownianMotionFitter(object):
    """This object fits Brownian motion position fluctuation data to
    calculate the spring constant of the cantilever and the
    detector noise floor.
    """

    def __init__(self, f, PSD, PSD_ci, T, est_cant):
        """
        f
            frequency (Hz)

        PSD
            Power spectral density of position fluctuations (nm^2 / Hz)

        PSD_ci
            The confidence intervals corresponding to the PSD data (nm^2 / Hz)

        T
            temperature (K)

        est_cant
            A unitted cantilever with f_c, k_c and Q defined as best guesses.

        """
        self.f = f
        self.PSD_raw = PSD
        self.PSD_ci_raw = PSD_ci
        self.T = T * u.K
        self.est_cant = est_cant

        self.rcParams = {}

    def _guess_P_detector(self):
        """Guess a low, but reasonable number for the detector noise floor.
        This is used to scale the data for fitting."""
        try:
            self.mask
        except AttributeError:
            # Make a dummy mask of all trues if no mask has been set
            self.mask = np.isfinite(self.PSD_raw)

        self.P_detector0_raw = np.percentile(self.PSD_raw[self.mask], 25)

    def _scale_data(self):
        """Scale the raw data for fitting, so that floating point number errors
        are not an issue."""
        self.PSD = self.PSD_raw / self.P_detector0_raw
        self.P_detector0 = 1

    def calc_fit(self, f_min=None, f_max=None):
        """Fit the power spectrum data over the frequency range
        f_min to f_min, using a 3 pass approach.

        If no f_min and f_max are provided, it fits over the entire range
        of input frequencies."""

        # Set f_min, f_max
        if f_min is None:
            self.f_min = self.f.min()
        else:
            self.f_min = f_min
        if f_max is None:
            self.f_max = self.f.max()
        else:
            self.f_max = f_max

        # Store a mask to aid fitting and plotting
        self.mask = mask = make_mask(self.f, self.f_min, self.f_max)

        self._guess_P_detector()
        self._scale_data()

        f = self.fit_f = self.f[mask]
        PSD = self.fit_PSD = self.PSD[mask]
        PSD_ci = self.PSD_ci = self.PSD_ci_raw[mask]
        self.fit_PSD_raw = self.PSD_raw[mask]

        self._calc_initial_params()

        self._first_pass(f, PSD, PSD_ci)
        self._second_pass(f, PSD, PSD_ci)
        self._final_pass(f, PSD, PSD_ci)
        self._prepare_output()

    def _calc_initial_params(self):
        """Use the estimates to calculate initial parameters to use for
        the fitting functions."""
        f_c = self.est_cant.f_c.to(u.Hz)
        k_c = self.est_cant.k_c.to(u.N/u.m)
        Q = self.est_cant.Q.magnitude

        P_x0guess = (calc_P_x0(f_c, k_c, Q, self.T) /
                    (self.P_detector0_raw * u.nm ** 2 / u.Hz))

        self.initial_params = [P_x0guess.magnitude, f_c.magnitude, Q]

    def _first_pass(self, f, PSD, PSD_ci):
        """Fit the power spectrum data using initial guesses for the
        parameters and a fixed noise floor. Fitting outputs stored in
        self.popt1, self.pcov1.

        We use user input guesses for the three cantilever parameters,
        and fix the thermal noise floor to a low but reasonable guess.
        Then, we fit the remaining three parameters :math:`P_{x0}, f_c, Q`.
        """

        def Pf_fixed_P_detector(f, P_x0, f_c, Q):
            return Pf(f, P_x0, f_c, Q, self.P_detector0)

        self.popt1, self.pcov1 = curve_fit(Pf_fixed_P_detector,
                                           f, PSD,
                                           p0=self.initial_params,
                                           sigma=PSD_ci)

    def _second_pass(self, f, PSD, PSD_ci):
        """Fit the power spectrum holding the center frequency :math:`f_c`
        fixed. Fitting outputs stored in self.popt2, self.pcov2."""
        f_c = self.popt1[1]

        def Pf_fixed_f_c(f, P_x0, Q, P_detector):
            return Pf(f, P_x0, f_c, Q, P_detector)

        p0 = [self.popt1[0], self.popt1[2], self.P_detector0]

        self.popt2, self.pcov2 = curve_fit(Pf_fixed_f_c,
                                           f, PSD,
                                           p0=p0,
                                           sigma=PSD_ci)

    def _final_pass(self, f, PSD, PSD_ci):
        """Fit the power spectrum allowing all parameters to
        determined by the fitting algorithm. Fitting outputs stored to
        self.popt, self.pcov.

        The fit data and raw fit data is stored to self.PSD_fit,
        self.PSD_fit_raw."""
        popt1, popt2 = self.popt1, self.popt2
        f_c = popt1[1]
        p0 = [popt2[0], f_c, popt2[1], popt2[2]]
        self.popt, self.pcov = curve_fit(Pf,
                                         f, PSD,
                                         p0=p0,
                                         sigma=PSD_ci)
        self.PSD_fit = Pf(f, *self.popt)
        self.PSD_fit_raw = self.PSD_fit * self.P_detector0_raw

    def _prepare_output(self):
        f_c, k_c, Q, P_detector = translate_fit_parameters(
            self.popt, self.pcov, self.P_detector0_raw, self.T)
        self.residuals = (self.PSD_fit - self.PSD[self.mask])
        self.reduced_residuals = self.residuals / self.PSD_fit
        self.reduced_residuals_sorted = np.sort(self.reduced_residuals)
        self._fit_residuals()
        self.f_c, self.k_c, self.Q, self.P_detector = f_c, k_c, Q, P_detector

    def report(self):
        return u"""
    Input
    -----------------------------------------------
    Temperature           T: {self.T:P}

    Estimates
    -----------------------------------------------
    Spring constant     k_c: {self.est_cant.k_c:P}
    Resonance frequency f_c: {self.est_cant.f_c:P}
    Quality factor        Q: {self.est_cant.Q:P}

    Fitting
    -----------------------------------------------
    Fit frequency min f_min: {f_min:P}
    Fit frequency max f_max: {f_max:P}

    Results
    -----------------------------------------------
    Resonance frequency f_c: {self.f_c:.1uSP}
    Spring constant     k_c: {self.k_c:.1uSP}
    Quality Factor        Q: {self.Q:.1uSP}
    Detector Noise         : {self.P_detector:.1uSP}
            """.format(self=self, f_min=self.f_min*u.Hz, f_max=self.f_max*u.Hz)

    def rst_report(self):
        return u"""
Report::

    Input
    -----------------------------------------------
    Temperature           T: {self.T:P}

    Estimates
    -----------------------------------------------
    Spring constant     k_c: {self.est_cant.k_c:P}
    Resonance frequency f_c: {self.est_cant.f_c:P}
    Quality factor        Q: {self.est_cant.Q:P}

    Fitting
    -----------------------------------------------
    Fit frequency min f_min: {f_min:P}
    Fit frequency max f_max: {f_max:P}

    Results
    -----------------------------------------------
    Resonance frequency f_c: {self.f_c:.1uSP}
    Spring constant     k_c: {self.k_c:.1uSP}
    Quality Factor        Q: {self.Q:.1uSP}
    Detector Noise         : {self.P_detector:.1uSP}
            """.format(self=self, f_min=self.f_min*u.Hz, f_max=self.f_max*u.Hz)

    def print_output(self):
        print(self.report())

# These plotting functions could use a refactor
# Lots of duplicated code, logic fairly separate from the rest of the class
    def plot_fit(self, filename=None):
        """Plot the calculated fit."""
        f = self.fit_f

        mpl.rcParams.update(self.rcParams)
        import matplotlib.pyplot as plt
        fig, ax = plt.subplots()

        ax.semilogy(f, self.fit_PSD_raw, f, self.PSD_fit_raw)

        ax.set_xlim(self.f_min, self.f_max)
        ax.set_xlabel('Frequency [Hz]')
        ax.set_ylabel(u'PSD [nm²/Hz]')

        fig.gca()
        fig.canvas.draw()
        fig.tight_layout(pad=0.25)

        if filename is not None:
            fig.savefig(filename)

        self.fit_fig, self.fit_ax = fig, ax
        return fig, ax

    def plot_residuals(self, filename=None):
        """Plot the residuals of the calculated fit."""

        mpl.rcParams.update(self.rcParams)
        import matplotlib.pyplot as plt

        fig, ax = plt.subplots()

        ax.plot(self.fit_f, self.residuals)

        ax.set_xlabel('Frequency [Hz]')
        ax.set_ylabel(u'Residual [nm²/Hz]')

        fig.gca()
        fig.canvas.draw()
        fig.tight_layout(pad=0.25)

        if filename is not None:
            fig.savefig(filename)
        return fig, ax

    def plot_reduced_residuals(self, filename=None):
        mpl.rcParams.update(self.rcParams)
        import matplotlib.pyplot as plt

        fig, ax = plt.subplots()

        ax.plot(self.fit_f, self.reduced_residuals)

        ax.set_xlabel('Frequency [Hz]')
        ax.set_ylabel('Normalized Residual')

        fig.gca()
        fig.canvas.draw()
        fig.tight_layout(pad=0.25)

        if filename is not None:
            fig.savefig(filename)
        return fig, ax

    def plot_cdf(self, filename=None):
        x = self.reduced_residuals_sorted
        size = x.size
        y = np.arange(1, 1 + size) / size
        popt = self.p_residuals

        mpl.rcParams.update(self.rcParams)
        import matplotlib.pyplot as plt

        fig, ax = plt.subplots()

        ax.plot(x, y, 'bo', x, cdf(x, *popt), 'g-')
        ax.set_xlabel("Reduced Residual")
        ax.set_ylabel("CDF")

        fig.gca()
        fig.canvas.draw()
        fig.tight_layout(pad=0.25)

        if filename is not None:
            fig.savefig(filename)
        return fig, ax

    def _fit_residuals(self):
        self.p_residuals = fit_residuals(self.reduced_residuals_sorted)
        print("""
Residuals
-------------------------------------
        Mean: {self.p_residuals[0]:.2e}
   Std. dev.: {self.p_residuals[1]:.2e}""".format(self=self))

def Pf(f, P_x0, f_c, Q, P_detector):
    """The equation to calculate :math:`P_x(f)` from the cantilever
    parameters and detector noise floor.

    f
        Frequency, the independent variable.

    P_x0
        The zero frequency power spectral density of position fluctuations.

    f_c
        The cantilever resonance frequency.

    Q
        The quality factor of the cantilever.

    P_detector
        The detector noise floor.
        """
    return (P_x0 * f_c**4 /
            ((f**2 - f_c**2)**2 + f**2 * f_c**2 / Q**2)
            + P_detector)

def make_mask(f, f_min, f_max):
    """Return a mask of the array f. The mask can be used
    to give only elements of f between fmin and fmax.

    Use the resulting mask to block off elements of f outside
    of the specified bounds, as shown below.

    >>> f = np.arange(10)
    >>> mask = make_mask(f, 1.5, 5.5)
    >>> f[mask]
    array([2, 3, 4, 5])
    """
    mask_low = f < f_max
    mask_high = f > f_min
    return np.logical_and(mask_high, mask_low)

def translate_fit_parameters(popt, pcov, P_detector0_raw, T=300*u.K):
    """Take the fit parameters and covariances, and converts them to
    SI values and errors for f_c, k_c, Q.

    Also makes sure all values are positive."""
    pvals = correlated_values(popt, pcov)
    punits = [u.nm**2 / u.Hz, u.Hz, u.dimensionless, u.nm**2 / u.Hz]
    scales = [P_detector0_raw, 1, 1, P_detector0_raw]

    def create_measurement(uncert_val, unit, scale):
        return (uncert_val.n * unit).plus_minus(uncert_val.s) * scale

    P_x0, f_c, Q, P_detector = [np.abs(
                                    create_measurement(uncert_val, unit, scale)
                                ) for
                                uncert_val, unit, scale in
                                zip(pvals, punits, scales)]

    k_c = np.abs(calc_k_c(f_c, Q, P_x0, T))
    return f_c, k_c, Q, P_detector

def calc_k_c(f_c, Q, P_x0, T=(300, 1)*u.K):
    """Calculate the spring constant, returning a pint quantity containing
    a value with uncertainty, if uncertainty is used on the input (ufloat)."""
    return ((2 * k_B * T) / (np.pi * f_c * Q * P_x0)).to(u.N / u.m)

def calc_P_x0(f_c, Q, k_c, T):
    """Calculate the thermal noise floor, returning a pint quantity in
    units of nm^2 / Hz."""
    return ((2 * k_B * T) / (np.pi * f_c * Q * k_c)).to(u.nm ** 2 / u.Hz)

def iterate_fit(func, x, y, p0, sigma_i, wgt):
    popt = [[]]
    pcov = [[]]
    popt[0], pcov[0] = curve_fit(func, x, y, p0=p0, sigma=sigma_i)
    for i in xrange(10):
        new_sigma = wgt * func(x, *popt[-1])
        opt, cov = curve_fit(func, x, y, p0=popt[-1], sigma=new_sigma)
        popt.append(opt)
        pcov.append(cov)
    PSD_fit = func(x, *popt[-1])
    return popt[-1], pcov[-1], PSD_fit

def avg_ci_data(data, axis=0):
    """Average the data along the given dimension, and calculate the 95
    percent confidence interval. Return the avg, ci arrays."""
    data_avg = data.mean(axis=axis)
    data_std = data.std(axis=axis, ddof=1)
    data_ci = data_std / data.shape[axis]**0.5 * 1.96
    return data_avg, data_ci

def get_data(filename_or_fh):
    """Extract power spectrum data from an HDF5 file.
    Return f, PSD_mean, PSD_conf_int.

    The HDF file should have the following structure:

    x
        A table containing the frequencies of each point in the power
        spectrum.

    y
        Contains power spectra PSD_0(f) through PSD_(n-1)(f), arranged
            as follows, with each power spectrum occupying 1 column.
        PSD_0(0 Hz) PSD_1(O Hz)
        PSD_0(1 Hz) PSD_1(1 Hz) ...

    y_std
        Contains standard deviations for the data points in y

    See http://h5labview.sourceforge.net and http://www.h5py.org for
    more information."""
    is_filename = isinstance(filename_or_fh, six.string_types)
    if is_filename:
        fh = h5py.File(filename_or_fh, 'r')
    else:
        fh = filename_or_fh

    # Put some checks about old-style files here.
    f = fh['x'].value
    PSD_mean = fh['y'].value
    PSD_ci = fh['y_std'].value * 1.96 / fh['y'].attrs['n_avg']**0.5

    if is_filename:
        fh.close()

    return f, PSD_mean, PSD_ci

def cdf(x, loc, scale):
    """The cumulative probability function of the normal distribution."""
    return sp.stats.norm.cdf(x, loc=loc, scale=scale)

def fit_residuals(sorted_residuals):
    """Return the result of fitting the residuals to the normal cdf.
    """
    size = sorted_residuals.size
    y = np.arange(1, 1 + size) / size

    popt, _ = curve_fit(cdf, sorted_residuals, y)

    return popt

def convert_data(oldfile, newfile, fileformat='v1'):
    """Converts data from the v1 format to the v2 format"""
    oldf = h5py.File(oldfile, 'r')
    if oldf.get('PSD', getclass=True) is not h5py.Group:
        oldf.close()
        raise ValueError("It appears you have inputted a new style file.\
            The file will not be converted.")
    else:
        newf = h5py.File(newfile, 'w')
        newf['f'] = oldf['f'][:]
        # Include any dataset that starts with a small d
        # This should catch the default d001, d0002, d003,
        data_list = [value for key, value in oldf['PSD'].items()
                     if key.startswith('d')]
        newf['PSD'] = np.empty((oldf['f'].value.size, len(data_list)))

        for i, val in enumerate(data_list):
            newf['PSD'][:, i] = val[:]
        oldf.close()
        newf.close()

def silentremove(filename):
    """If a file exists, delete it. Otherwise, return nothing.
       See http://stackoverflow.com/q/10840533/2823213"""
    try:
        os.remove(filename)
    except OSError as e:  # this would be "except OSError, e:" before Python 2.6
        if e.errno != errno.ENOENT:  # errno.ENOENT = no such file or directory
            raise  # re-raise exception if a different error occured

from ._version import get_versions
__version__ = get_versions()['version']
del get_versions


import torch

import src.inferencers.infbase

class Inf1(src.inferencers.infbase.Inferencer):
    def __init__(self, dataloaderfactory, model, state_path):
        self.dataloaderfactory = dataloaderfactory
        self.config = src.util.config.Config()
        self.testloader = dataloaderfactory.gettestloader()
        self.model = model
        state = torch.load(state_path, map_location=lambda storage, loc: storage)
        self.model.load_state_dict(state["state_dict"])
        self.device = torch.device("cuda:0")
        self.model.to(self.device)

    def run(self):
        inputs, labels = next(iter(self.testloader))
        inputs = inputs.to(self.device)
        labels = labels.to(self.device)

        pred = self.model(inputs)
        pred = torch.sigmoid(pred)
        pred = pred.data.cpu().numpy()
        # # print(pred.shape)
        # if self.config.dataloader_print_inferencer_num > 0:
        #     self.dataloaderfactory.print_testexample(
        # inputs, pred, labels,
        # count=self.config.dataloader_print_inferencer_num,
        # printfolder=self.config.dataloader_printfolder, printfile="pred.png")
        # print("")

'''
        inputs, labels = next(iter(self.gettestloader()))
        inputs = inputs.to(device)
        labels = labels.to(device)

        pred = model(inputs)
        pred = torch.sigmoid(pred)
        pred = pred.data.cpu().numpy()
        print(pred.shape)

        # Change channel-order and make 3 channels for matplot
        input_images_rgb = [reverse_transform(x) for x in inputs.cpu()]

        # Map each channel (i.e. class) to each color
        target_masks_rgb = [helper.masks_to_colorimg(x) for x in labels.cpu().numpy()]
        pred_rgb = [helper.masks_to_colorimg(x) for x in pred]

        helper.plot_side_by_side([input_images_rgb, target_masks_rgb, pred_rgb])

import torch
import src.util.config

class InferenceModel:
    def __init__(self, dataloaderfactory, state_path, model):
        state = torch.load(state_path, map_location=lambda storage, loc: storage)
        model.load_state_dict(state["state_dict"])
        pass
        '''


from django.http import HttpResponseRedirect
from django.urls import reverse
from rest_framework.request import Request
from rest_framework.response import Response

from sentry.models.group import Group, GroupStatus

from .react_page import ReactPageView

class NewestPerformanceIssueView(ReactPageView):
    def handle(self, request: Request, organization, **kwargs) -> Response:
        group = (
            Group.objects.filter(
                project_id__in=request.access.accessible_project_ids,
                status=GroupStatus.UNRESOLVED,
                # performance issue range
                type__gte=1000,
                type__lt=2000,
            )
            .order_by("-first_seen")
            .first()
        )
        if group:
            return HttpResponseRedirect(
                reverse("sentry-organization-issue", args=[organization.slug, group.id])
            )
        # if no group, then redirect to the issues page
        return HttpResponseRedirect(
            reverse("sentry-organization-issue-list", args=[organization.slug])
        )


from collections import defaultdict
items = []
DEFAULT_VALUE = "000000000000000000000000000000000000"
mem = defaultdict(lambda:DEFAULT_VALUE)
mask = ""
with open ('YourfileHere_Puzzle14.txt') as f:
    for line in f:
        line = line.rstrip("\n")
        items.append(line)

"""First part of the puzzle
"""
# def changebits(mask,value):
#     new_value= []
#     ones_to_change = [i for i,x in enumerate(mask) if x == "1"]
#     zero_to_change = [i for i,x in enumerate(mask) if x == "0"]
#     for i,x in enumerate(value):
#         if i in ones_to_change:
#             new_value.append("1")
#         elif i in zero_to_change:
#             new_value.append("0")
#         else:
#             new_value.append(x)
#     new_value = "".join(new_value)
#     return(new_value)

# # print(items[2].split()[0].strip("mem[").strip("]")) #this is to obtain the memory address we will change
# for instruction in items:
#     print(instruction)
#     if instruction.split()[0] == "mask":
#         mask = instruction.split()[2]
#         continue
#     else:
#         address = instruction.split()[0].strip("mem[").strip("]")
#         value = "{:036b}".format(int(instruction.split()[2]))
#         mem[address] = changebits(mask,value)

# suma = 0
# for i in mem.values():
#     suma += int(i,2)
# print(suma)

"""Second part of the puzzle
"""

def changebits(mask,value):
    new_value= []
    ones_to_change = [i for i,x in enumerate(mask) if x == "1"]
    floating_to_change = [i for i,x in enumerate(mask) if x == "X"]
    for i,x in enumerate(value):
        if i in ones_to_change:
            new_value.append("1")
        elif i in floating_to_change:
            new_value.append("X")
        else:
            new_value.append(x)
    new_value = "".join(new_value)
    return(new_value)

# it = [None] * 3 #for backtracking
# def permutations_item(value,iterables,count): Backtracking
#     if count == value:
#         return
#     iterables[count] = 0
#     permutations_item(value,iterables,count + 1)
#     iterables[count] = 1
#     permutations_item(value,iterables,count + 1)

def find_mask_Bits(mask):
    return [i for i, j in enumerate(mask) if j == "X"]

def generate_binary(n, l):
    if n == 0:
        return l
    else:
        if len(l) == 0:
            return generate_binary(n-1, ["0", "1"])
        else:
            return generate_binary(n-1, [i + "0" for i in l] + [i + "1" for i in l])

def modify_mask(mask,iter_item):
    count = 0
    temp_mask = list(mask)
    for item in find_mask_Bits(mask):
        temp_mask[item] = iter_item[count]
        count += 1
    temp_mask = "".join(temp_mask)
    return(temp_mask)

for instruction in items:  # we pass through
    #print(instruction)
    if instruction.split()[0] == "mask":
        mask = instruction.split()[2]
        continue
    else:
        iterated = [] # this is used to create a list with all the combinations of 0/1 of x lenght
        value = int(instruction.split()[2])  #this is the value that will be added to the dictionary address
        address = instruction.split()[0].strip("mem[").strip("]") # we retrieve the address the value should go
        address_bin =  "{:036b}".format(int(address))   #transformed in binary with lenght 36
        masked_address = changebits(mask,address_bin) # we do the mask transformation to the previously transforme value
        permutations = generate_binary(len(find_mask_Bits(masked_address)),iterated)  # generate the permutations each X can have
        for i in permutations: #for all the permutations generated, we put the value
            mem[int(modify_mask(masked_address,i),2)] = value

suma = 0
for i in mem.values():
    suma += i
print(suma)


# Libraries
import pygame
import time
from datetime import datetime

# Engine
from engine_v2.game import Game

# Constants
from pygame.constants import *
from engine_v2.constants import *

# Components
from v7.player import Player
from v7.enemy import Enemy
from v7.barrier import Barrier
from v7.win_logic import check_for_win

sorted_scores = []
game_finish_time = None
win_area = ((46.5, 47.5), (1, 13))

# 1. Initialize game
game = Game(
    width=50 * SCALING_FACTOR,
    height=20 * SCALING_FACTOR,
    print_fps=False, max_fps=MAX_DRAW_FPS
)

# 2. Initialize graphics
# Graphics have to be import after the game has been initialized! (Pygame constraint)
from v7.graphics import *

# 3. Initialize players & pass the sprites from v6.graphics
player_1 = Player(
    "Max", color=(220, 74, 123), position=(21.5, 12), **player_1_sprites,
    keymap={K_w: 'UP', K_a: 'LEFT', K_s: 'DOWN', K_d: 'RIGHT'}
)
player_2 = Player(
    "Moritz", color=(218, 78, 56), position=(14.5, 12), **player_2_sprites,
    keymap={K_UP: 'UP', K_LEFT: 'LEFT', K_DOWN: 'DOWN', K_RIGHT: 'RIGHT'}
)

# 4. Initialize enemies
for x in range(2, 32, 3):
    Enemy(position=(x, 2))
    pass

# 5. Initialize barriers
Barrier(x_left=-1, y_top=21, width=52, height=1)  # window top
Barrier(x_left=-1, y_top=1, width=52, height=1)  # window bottom
Barrier(x_left=-1, y_top=21, width=1, height=22)  # window left
Barrier(x_left=50, y_top=21, width=1, height=22)  # window right

Barrier(x_left=12, y_top=6, width=5, height=1)  # step 1
Barrier(x_left=19, y_top=8, width=5, height=1)  # step 2
Barrier(x_left=26, y_top=10, width=5, height=1)  # step 3

Barrier(x_left=36, y_top=9, width=2, height=8)  # pyramid column 1
Barrier(x_left=38, y_top=7, width=2, height=6)  # pyramid column 2
Barrier(x_left=40, y_top=5, width=2, height=4)  # pyramid column 3
Barrier(x_left=42, y_top=3, width=2, height=2)  # pyramid column 4

def update(timedelta):
    # Only the moving objects have to be updated
    Enemy.update_all(timedelta)
    Player.update_all(timedelta)

def draw():
    # 1. Draw game elements
    game.draw_background()
    Barrier.draw_all(game)
    draw_winning_pole(game)
    Enemy.draw_all(game)
    Player.draw_all(game)

    # 2. Draw scores if score-list is not empty
    draw_scores(game, sorted_scores)

    # 3. Draw text in top left corner
    if DRAW_HELPERS:
        draw_debug_stats(game, player_1)
    else:
        draw_player_stats(game, player_1, player_2)

    # 4. Draw bottom left fps
    draw_fps(game)

    # 5. Update game window (and fps)
    game.update()

def run():
    global sorted_scores
    global game_finish_time

    # After game_finish_time has been set from inside check_for_win
    # The game will continue to run for 8 seconds and then end
    while game_finish_time is None or (datetime.now() - game_finish_time).seconds < 8:

        # 1. Attach event handler
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                game.exit()

            if event.type in (pygame.KEYDOWN, pygame.KEYUP):
                if event.key in (pygame.K_w, pygame.K_a, pygame.K_s, pygame.K_d):
                    player_1.keypress(event.key, event.type == pygame.KEYDOWN)
                if event.key in (pygame.K_UP, pygame.K_LEFT, pygame.K_DOWN, pygame.K_RIGHT):
                    player_2.keypress(event.key, event.type == pygame.KEYDOWN)

        # 2. Update (simulation)
        if not SLOWDOWN:
            # Collision detection is not fully working with very
            # low fps (<< 10 fps)
            fps = max(game.fps, MIN_DRAW_FPS)

            # Solution: Simulate multiple time steps per drawing
            # because drawing takes > 250 times longer than
            # simulating
            for i in range(SIMULATION_FRAMES_PER_DRAW):
                update(1/(fps * SIMULATION_FRAMES_PER_DRAW))

                # Check for a possible game ending
                sorted_scores, game_finish_time = check_for_win(win_area, sorted_scores, game_finish_time)

        else:
            # SLOWDOWN can be set to true in order to observe the
            # in extreme slow_motion. How many fps with SLOWDOWN
            # enabled can be set with SLOWDOWN_FPS
            time.sleep((1/SLOWDOWN_FPS) - (1/100))
            update(1/100)

        # 3. Draw (visualization)
        draw()


#!/usr/bin/env python3

#
# Jasy - Web Tooling Framework
# Copyright 2010-2012 Zynga Inc.
# Copyright 2013-2014 Sebastian Werner
#

# Import standard library stuff
import sys, os.path, json, logging

# Version check
if sys.version_info[0] < 3:
    sys.stderr.write("Jasy requires Python 3!\n")
    sys.exit(1)

# Include local Jasy into Python library path
basedir = os.path.join(os.path.dirname(sys.argv[0]), os.pardir)
if os.path.exists(os.path.join(basedir, "jasy")):
    sys.path.insert(0, basedir)

if len(sys.argv) == 1:
    sys.stderr.write("Missing job name\n")
    sys.exit(1)

supported = set(("tokens", "tree", "compress", "optimize", "reduced"))
job = sys.argv[1]
if not job in supported:
    sys.stderr.write("Invalid job %s\n" % job)
    sys.exit(1)

logging.basicConfig(level=logging.DEBUG, format="%(message)s")

import jasy

import jasy.style.Engine as Engine
import jasy.style.output.Formatting as Formatting

for fname in sys.argv[2:]:
    text = open(fname, encoding="utf-8").read()

    print(">>> File: %s" % fname, file=sys.stderr)

    if job == "optimize":
        tree = Engine.getTree(text, fname)
        tree = Engine.reduceTree(tree)
        print(Engine.compressTree(tree))

    elif job == "compress":
        formatting = Formatting.Formatting("blocks", "whitespace", "statements", "indent")
        tree = Engine.getTree(text, fname)
        tree = Engine.reduceTree(tree)
        print(Engine.compressTree(tree, formatting))

    elif job == "reduced":
        formatting = Formatting.Formatting("blocks", "whitespace", "statements", "indent")
        tree = Engine.getTree(text, fname)
        tree = Engine.reduceTree(tree)
        print(tree.toXml())

    elif job == "tree":
        tree = Engine.getTree(text, fname)
        print(tree.toXml())

    elif job == "tokens":
        Engine.printTokens(text, fname)


import pytest
from common.log import logger
from test_case.persistentvolumes.pv import Pv

@pytest.mark.BAT
@pytest.mark.ace
@pytest.mark.flaky(reruns=2, reruns_delay=3)
class TestPvSuite(object):
    def setup_class(self):
        self.pv = Pv()
        self.pv_name = 'alauda-pv-{}'.format(self.pv.region_name).replace('_', '-')
        self.teardown_class(self)

    def teardown_class(self):
        self.pv.delete_pv(self.pv_name)

    def test_pv(self):
        result = {"flag": True}

        # create pv
        create_result = self.pv.create_pv("./test_data/pv/pv.json",
                                          {"$pv_name": self.pv_name, "$size": "1",
                                           })
        assert create_result.status_code == 201, "创建pv失败{}".format(create_result.text)
        self.pv.check_value_in_response(self.pv.get_common_pv_url(), self.pv_name, params={})
        # list pv
        list_result = self.pv.list_pv()
        result = self.pv.update_result(result, list_result.status_code == 200, list_result.text)
        result = self.pv.update_result(result, self.pv_name in list_result.text, "获取持久卷列表：新建pv不在列表中")
        # update pv
        update_result = self.pv.update_pv(self.pv_name, "./test_data/pv/pv.json",
                                          {"$pv_name": self.pv_name, "$size": "2",
                                           })
        assert update_result.status_code == 204, "更新pv失败{}".format(update_result.text)
        # get pv detail
        detail_result = self.pv.get_pv_detail(self.pv_name)
        logger.info(detail_result.text)
        result = self.pv.update_result(result, detail_result.status_code == 200, detail_result.text)
        result = self.pv.update_result(result,
                                       self.pv.get_value(detail_result.json(),
                                                         "kubernetes.status.phase") == "Available",
                                       "获取持久卷详情失败：状态不是可用")
        result = self.pv.update_result(result,
                                       self.pv.get_value(detail_result.json(),
                                                         "kubernetes.spec.capacity.storage") == "2Gi",
                                       "获取持久卷详情失败：大小不是2Gi")
        # delete pv
        delete_result = self.pv.delete_pv(self.pv_name)
        assert delete_result.status_code == 204, "删除pv失败{}".format(delete_result.text)
        exists_result = self.pv.check_exists(self.pv.get_common_pv_url(self.pv_name), 404)
        assert exists_result, "删除持久卷失败"
        assert result['flag'], result


# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright 2015-2016 by EcpyPulses Authors, see AUTHORS for more details.
#
# Distributed under the terms of the BSD license.
#
# The full license is in the file LICENCE, distributed with this software.
# -----------------------------------------------------------------------------
"""Check that the manifest does register the editor.

"""
from __future__ import (division, unicode_literals, print_function,
                        absolute_import)

from collections import OrderedDict

import enaml
import pytest

from ecpy.testing.util import show_widget

with enaml.imports():
    from ecpy_pulses.pulses.manifest import PulsesManagerManifest
    from ecpy_pulses.measure.manifest import PulsesMeasureManifest

from ...tasks.tasks.test_transfer_sequence_task import task, sequence
with enaml.imports():
    from ...pulses.contributions import PulsesContributions

pytest_plugins = (str('ecpy.testing.measure.fixtures'),)

@pytest.fixture
def editor(measure_workbench):
    """Create a pulse sequence editor.

    """
    measure_workbench.register(PulsesManagerManifest())
    measure_workbench.register(PulsesMeasureManifest())
    measure_workbench.register(PulsesContributions())
    pl = measure_workbench.get_plugin('ecpy.measure')

    decls = pl.get_declarations('editor', ['ecpy_pulses.pulse_sequence'])
    decl = decls['ecpy_pulses.pulse_sequence']
    ed = decl.new(measure_workbench)
    return ed

def test_sequence_vars_update(measure_workbench, editor, task,
                              process_and_sleep, windows):
    """Test that when unselecting the editor we properly synchronize the vars.

    """
    task.sequence_vars = OrderedDict({'a': '1.5', 'b': '2'})
    win = show_widget(editor)
    editor.selected_task = task
    process_and_sleep()

    root_view = editor.page_widget().widgets()[0].scroll_widget().widgets()[0]
    vars_editor = root_view.additional_pages[0]
    vars_editor.page_widget().widgets()[0].text = 'a, c'

    editor.react_to_unselection(measure_workbench)
    assert task.sequence_vars == OrderedDict([('a', '1.5'), ('c', '')])
    win.close()

def test_sequence_replacement(editor, task, windows, process_and_sleep):
    """Test replacing the sequence (a priori not possible).

    """
    editor.selected_task = task
    show_widget(editor)

    root_view = editor.page_widget().widgets()[0].scroll_widget().widgets()[0]
    old = root_view.additional_pages[0]

    seq = task.sequence
    task.sequence = sequence()
    process_and_sleep()
    task.sequence = seq
    process_and_sleep()

    root_view = editor.page_widget().widgets()[0].scroll_widget().widgets()[0]
    process_and_sleep()
    new = root_view.additional_pages[0]

    assert old is not new


# find max of a monotonically increasing/decreasing sequence
import pdb

# O(log(n))
# doesn't work...
def find_max2(a, b=1):
    print('b = {}; a[b:] = {}'.format(b, a[b:]))
    if len(a) == 1:
        return 1
    if a[b-1] > a[b]:
        return a[b-1]

    if a[b+1] > a[b] and 2*b < len(a):
        return find_max(a, 2*b)
    else:
        return find_max(a[b:])

# works
def find_max3(a, i=0):
    print('a[{}:] = {}'.format(i, a[i:]))
    if len(a[i:]) == 1:
        return a[i]
    if a[i+1] > a[i]: # if increasing
        if 2*(i+1) > len(a): # if you can't double the index
            return find_max(a, i + ((len(a)-i)/2) )
        return find_max(a, 2*(i+1)) # search next half
    else: # if decreasing
        return find_max(a, (i+1)/2) # search prev half

# works
def find_max4(a, i=0, j=None):
    if j == None:
        j = len(a)

    print('a[{}:{}] = {}'.format(i, j, a[i:j]))

    if len(a[i:j]) == 1:
        return a[i]

    if a[i+1] > a[i]: # if increasing, search next half
        return find_max(a, i + (j - i)/2, j)
    else: # if decreasing, search prev half
        return find_max(a, i - (j - i)/2, i + 1)

# bsearch method
def bsearch(a):
    if len(a) == 1:
        return 0
    if len(a) == 2:
        return a.index(max(a))

    m = len(a)/2
    print('a = {}; a[{}] = {}'.format(a, m, a[m]))
    if a[m] < a[m+1]:
        return m + bsearch(a[m:])
    else:
        return bsearch(a[:m+1])

def find_max(a):
    return a[bsearch(a)]

# using iteration O(n)
def find_max5(a):
    for i in range(len(a)-1):
        if a[i] > a[i+1]:
            return a[i]

    return a[-1]

if __name__=='__main__':
    a = [1,2,5,6,20,21,24,25,26,27,28,90,80,70,60,59,58,57,55,55,54,53,52,40,39,38,37,36]
    print('length(a) = {}'.format(len(a)))
    print(find_max5(a))
    pdb.set_trace()


#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
@author : Romain Graux
@date : 2020 Jun 30
@last modified : 2021 Apr 06, 17:15:11
"""

import math
import numpy as np
from copy import copy
from operator import mul
from functools import reduce
from tabulate import tabulate

from from_scratch.layers.core import Layer
from from_scratch.activations import get_activation_function
from from_scratch.kernel_initializers import get_kernel_initializer, populate_kernel

class Dense(Layer):
    def __init__(
        self,
        n_neurons,
        weights_initializer="lecun_uniform",
        biases_initializer="zeros",
        activation=None,
        input_shape=None,
    ):
        super().__init__()
        self.input_neurons = None
        self.n_neurons = n_neurons
        self.activation = activation
        self.initialized = False
        self.compiled = False
        self.inputs = None
        self.weights = None
        self.biases = None
        self.weights_initializer = weights_initializer
        self.biases_initializer = biases_initializer
        self.weights_optim = None
        self.biases_optim = None
        if input_shape is not None:
            self.initialize(input_shape)

    def initialize(self, input_shape):
        if not isinstance(input_shape, tuple):
            input_shape = tuple(input_shape)
        assert len(input_shape) == 1
        self.input_shape = input_shape
        self.output_shape = (self.n_neurons,)
        self.input_neurons = input_shape[0]

        self.weights = populate_kernel(
            kernel_initializer=self.weights_initializer,
            shape=(self.input_neurons, self.n_neurons),
        )
        self.biases = populate_kernel(
            kernel_initializer=self.biases_initializer, shape=(1, self.n_neurons)
        )

        self.parameters = reduce(mul, self.weights.shape) + reduce(
            mul, self.biases.shape
        )
        self.initialized = True

    def compile(self, optimizer):
        self.weights_optim = copy(optimizer)
        self.biases_optim = copy(optimizer)
        self.compiled = True

    def forward(self, x):
        if not self.initialized:
            self.initialize(x.shape[1])

        self.inputs = x
        self.output = np.matmul(x, self.weights) + self.biases
        return self.output

    def backward(self, grad, get_all=False):
        assert self.compiled and self.initialized

        grad_inputs = np.matmul(grad, self.weights.T)
        grad_weights = np.matmul(self.inputs.T, grad)
        grad_biases = np.sum(grad, axis=0, keepdims=True)

        self.weights = self.weights_optim.update(self.weights, grad_weights)
        self.biases = self.biases_optim.update(self.biases, grad_biases)

        if get_all:
            return dict(weights=grad_weights, biases=grad_biases, inputs=grad_inputs)
        return grad_inputs

class Flatten(Layer):
    def __init__(self, input_shape=None):
        super().__init__()
        self.compiled = True
        self.batch_size = None
        if input_shape is not None:
            self.initialize(input_shape)

    def initialize(self, input_shape):
        if not isinstance(input_shape, tuple):
            input_shape = tuple(input_shape)
        self.input_shape = input_shape
        self.output_shape = (reduce(mul, input_shape),)
        self.initialized = True

    def forward(self, x):
        self.batch_size = x.shape[0]
        if not self.initialized:
            self.initialize(x.shape[1:])

        return x.reshape((self.batch_size, -1))

    def backward(self, grad):
        return grad.reshape((self.batch_size,) + self.input_shape)

class Activation(Layer):
    def __init__(self, activation, input_shape=None):
        super().__init__()
        self.compiled = True
        self.inputs = None

        if input_shape is not None:
            self.initialize(input_shape)

        self.activation = get_activation_function(activation)

    def initialize(self, input_shape):
        if not isinstance(input_shape, tuple):
            input_shape = tuple(input_shape)
        self.input_shape = self.output_shape = input_shape

        self.parameters = 0
        self.initialized = True

    def forward(self, x):
        if not self.initialized:
            self.initialize(tuple(x[1:]))
        self.inputs = x
        return self.activation(x)

    def backward(self, grad):
        return self.activation.gradient(self.inputs) * grad

    def layer_name(self):
        return f"Activation ({self.activation.__class__.__name__})"


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2019-08-07 18:24:01
# @Author  : Yaohui Zhu (you@example.org)
# @Link    :
# @Version : $Id$

import os,re,configparser
import xlrd,time
from path import myPath
import tool

#################################################################
###############此部分应用于将Tracker Excel文件读取至页面及处理######
#################################################################

class dealExcel():
    def __init__(self,excel_path,dic):
        self.excel_path=excel_path

        # to deal with excel_path to protocol path
        excel_path_2 = myPath(init_path=self.excel_path)
        self.path_init = excel_path_2.getPathOfWin(type='init')
        print(self.path_init)
        self.compTime()

        s_adam         = self.path_init+'/dev/crts/adam'
        s_log          = self.path_init+'/dev/pgm/tlfs'
        v_log          = self.path_init+'/val/pgm/tlfs'
        self.adam_time         = self.getTime(filePath = s_adam,  type='sas7bdat')
        self.log_inf_source = self.getTime(filePath = s_log,   type='log')
        self.log_inf_val    = self.getTime(filePath = v_log,   type='log')
        print(len(self.adam_time),len(self.log_inf_source),len(self.log_inf_val))
        # to get all  pdf and rtf files from folder
        # self.rtfFiles = getFileName(self.path_init,'rtf')
        # self.pdfFiles = getFileName(self.path_init,'pdf')
        # cfg         = tool.getCfg()#获得配置信息

        # dic         = cfg.cfg()
        # dic  = tool.cfg()
        dic_cols    = dic
        print(dic_cols)
        self.book   = xlrd.open_workbook(self.excel_path)
        self.table  = self.book.sheet_by_name("TFL")
        self.nrows  = self.table.nrows
        self.ncols  = self.table.ncols
        # self._type                = 1 -1
        # self.analysis             = 2 -1
        self.tfl_category         = int(dic_cols['tfl_category'])
        # self.population           = 4 -1
        self.titles               = int(dic_cols['titles'])
        self.output_number        = int(dic_cols['output_number'])
        self.base_output_name     = int(dic_cols['base_output_name'])
        self.source_program_name  = int(dic_cols['source_program_name'])
        self.source_data          = int(dic_cols['source_data'])
        self.source_programmer    = int(dic_cols['source_programmer'])
        self.qc_programmer        = int(dic_cols['qc_programmer'])
        self.qc_program_name      = int(dic_cols['qc_program_name'])

    #9代表ssource program 所在的列
    #18是总的列数
    def getNrows(self):
        return self.nrows-1

    def excelDisplay(self ):

        # self.nrows=100

        all_the_final=[]

        for row in range(1,self.nrows):

            new_row_data=[]

            row_data = self.table.row_values(row, start_colx=0, end_colx=None)

            # _type               =       row_data[self._type]
            # analysis            =       row_data[self.analysis ]
            tfl_category        =       row_data[self.tfl_category ]
            # population          =       row_data[self.population]
            titles              =       row_data[self.titles]
            output_number       =       str(row_data[self.output_number])
            base_output_name    =       row_data[self.base_output_name]
            source_program_name =       row_data[self.source_program_name]
            source_data         =       row_data[self.source_data]
            source_programmer   =       row_data[self.source_programmer]
            qc_programmer       =       row_data[self.qc_programmer]
            qc_program_name       =     row_data[self.qc_program_name ]

            # temp_row=[row_data[row] for row in [0,2]]+row_data[7:14]
            #######################################################################
            ######################参照m_run_trk.sas 处理 fileout RTF_out############
            #######################################################################

            if output_number.strip() != '':

                _output_number =  output_number.strip().replace(".", "-")

            if tfl_category.strip() != '':

                in_num=tfl_category.index(':')

                _tfl_category = tfl_category[0:in_num]

                # print(_tfl_category)

            if base_output_name.strip() != '':

                typef           =   base_output_name.replace(" ",'').lower()[0]

                _base_outname   =   base_output_name.lower().replace("_", "-").replace(' ','').replace('.rtf','')

                _base_outname   =   _base_outname.replace(".pdf",'')[2:]

            if self.excel_path.find('/iss/') > -1 and self.excel_path.find('/ise/') > -1:
                fileout=''
            else:
                if typef.strip() == "l"  and tfl_category.find('DO NOT') == -1:
                    fileout='16.2'
                elif typef.strip() in ['t','f']:
                    fileout='14'
                else:fileout=''

            if typef.strip() in ['t','l','f']  and _tfl_category.strip() != ''   and _output_number.strip != '' and \
            base_output_name.strip() != '':
                RTF_Out = typef +'-'+ fileout.replace(".", "-") +'-'+ _tfl_category +'-'+ _output_number +'-'+_base_outname
                RTF_Out = RTF_Out.lower()

            else:
                RTF_Out = '';

            if typef in ['t','l','f'] and _tfl_category.strip() != '' and output_number !='':
                if self.excel_path.find('/iss/') > -1 :
                    if typef =='l' :
                        fileout = "Listing " + _tfl_category.replace("-", ".").replace(' ','') + '.'+output_number.strip()
                    elif typef =='t':
                        fileout = "Table " + _tfl_category.replace("-", ".").replace(' ','') + '.'+output_number.strip()
                    elif typef== 'f':
                        fileout = "Figure " + _tfl_category.replace("-", ".").replace(' ','') + '.'+output_number.strip()

                else:
                    if typef == 'l' :
                        fileout="Listing " + fileout.strip() + '.' + _tfl_category.replace("-", ".").replace(' ','') + '.'+output_number.strip()
                    elif typef =='t':
                        fileout = "Table " + fileout.strip() + '.' + _tfl_category.replace("-", ".").replace(' ','') + '.'+output_number.strip()
                    elif typef== 'f':
                        fileout = "Figure " + fileout.strip() + '.' + _tfl_category.replace("-", ".").replace(' ','') + '.'+output_number.strip()

            #############################################end####################################
            new_row_data=[fileout,base_output_name,RTF_Out,source_program_name,source_data,source_programmer,qc_programmer,qc_program_name]
            # print(new_row_data)

            ####################################################################################
            #############################处理source data 及ADAM的日期############################
            ####################################################################################

            list_temp=self.deal_log(row_data, self.adam_time, self.log_inf_source, self.log_inf_val)

            # print(list_temp)

            new_row_data += list_temp

            new_row_data = self.get_rtf_pdf(new_row_data)

            new_row_data.insert(0,"<input id=\"%s\"  type='checkbox' name=\"check_id\" value=\"\" >"%row)
            # new_row_data += ['']

            all_the_final.append(new_row_data)

        # print(all_the_final)
        return all_the_final

    ####################################################################################
    #############################处理source data 及ADAM的日期############################
    ####################################################################################
    def deal_adam(self,adam_time,row_data):

        # source_data = row_data[self.source_data].upper()
        # source_list = re.findall('AD[A-Z]{2,6}',source_data)
        # time_list=[]
        # for pair in adam_time:
        #     for adam in source_list:
        #         if pair[0].strip().lower() == adam.lower():
        #             time_of_adam=time.mktime(time.strptime(pair[1],'%Y-%m-%d %H:%M'))
        #             time_list.append(time_of_adam)
        # if len(time_list)>1:
        #     temp_2 = max(time_list)
        # else:
        #     return ' '
        # timeArray = time.localtime(temp_2)
        # finalTime = time.strftime("'%Y-%m-%d %H:%M'", timeArray)
        # print('this is finalTime of adam')
        # print(finalTime)
        source_data = row_data[self.source_data].upper()
        source_list = re.findall('AD[A-Z]{2,6}',source_data)
        time_list=[]
        for pair in adam_time:
            for adam in source_list:
                if pair[0].strip().lower() == adam.lower():
                    time_of_adam=pair[1]
                    time_list.append(time_of_adam)
        if len(time_list)>1:
            temp_2 = max(time_list)
        else:
            return ' '
        timeArray = time.localtime(temp_2)
        finalTime = time.strftime("'%Y-%m-%d %H:%M'", timeArray)
        return finalTime

    def deal_log(self, row_data, adam_time, log_inf_source, log_inf_val):

        adam_time_new = self.deal_adam(adam_time,row_data)
        # print(adam_time_new)
        #/////////////////////////////////////////////////
        #根据log获得表run的时间
        #/////////////////////////////////////////////////
        log_inf_source = [x for x in log_inf_source if len(x)>1]
        #定义sas code的列
        source_log = 0
        log_link = ''
        for j in log_inf_source:
            if row_data[self.source_program_name ].strip()[-4:] == ".sas":
                temp = row_data[self.source_program_name ].strip()[:-4]
            else:
                temp = row_data[self.source_program_name ].strip()

            if temp == j[0]:
                source_log = j[1]#get time of log of source pgm
                log_link   =  "LOG"
        # #/////////////////////////////////////////////////
        # #根据log获得表QC的时间
        # #/////////////////////////////////////////////////
        val_log=0
        for j in log_inf_val:
            if row_data[self.qc_program_name].strip()[-4:] == ".sas":
                temp=row_data[self.qc_program_name].strip()[:-4]
            else:
                temp=row_data[self.qc_program_name].strip()
            if temp == j[0]:
                val_log = j[1]#get time of log of val pgm

        #///////////////////////////////////////
        # yy to html
        # row_data.insert(0,"<input id=\"%s\"  type='checkbox' name=\"check_id\" value=\"\" >"%i)

        #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        #compare source and validation time of logs
        check=""
        t1=0
        t2=0
        if val_log != 0 and source_log != 0 :
            # t1=time.mktime(time.strptime(source_log,'%Y-%m-%d %H:%M'))
            # t2=time.mktime(time.strptime(val_log,'%Y-%m-%d %H:%M'))
            if source_log>val_log:
                check += "/QC U"
        if val_log == 0:
            check += "/No Val Log"
        if source_log == 0:
            check += "/No Dev Log"

        ################################################################
        ###################比较ADAM时间与source 时间######################
        adam_time_n=0
        if adam_time_new != ' ':
            adam_time_n = time.mktime(time.strptime(adam_time_new.replace("'", ''),'%Y-%m-%d %H:%M'))
        if adam_time_n >= source_log:
            check += "/ADAM"

        return [source_log,val_log,check,log_link]

    def get_rtf_pdf(self,new_row_data):

        rtf_link = ''
        pdf_link = ''
        # print(new_row_data)
        # new_row_data[2] to get RTF_out in new_raw_data
        rtf_out = new_row_data[2]
        if rtf_out != '':
            file_type = rtf_out[0]
        else:
            new_row_data =new_row_data + ['','']
            return new_row_data
        # print(self.rtfFiles)
        time_rtf = 0
        time_pdf = 0
        if  rtf_out in self.rtfFiles.keys():
            time_rtf = self.rtfFiles[rtf_out]
            rtf_link = "RTF"
            if rtf_out.find('intext') != -1:
                rtf_link = "RTF"
        if rtf_out in self.pdfFiles.keys():
            time_pdf = self.pdfFiles[rtf_out]
            pdf_link = "PDF"

        time_source_log     = new_row_data[8] #now the source_log_time in column 7

        time_source         = max([time_rtf,time_pdf,time_source_log] )

        #如果log存在，但是时间早于rtf,pdf 那么需要提醒

        if time_source_log != 0 and time_source != time_source_log:
            new_row_data[10] += "log pdf"

        timeArray = time.localtime(time_source)

        otherStyleTime = time.strftime("%Y-%m-%d %H:%M", timeArray)

        new_row_data[8] = otherStyleTime
        #如果source log缺失，应该标记为缺失log，而不是三者的最大值
        if time_source_log == 0:
            new_row_data[8] = "No log"
        # ///val_log
        time_val_log     = new_row_data[9] #now the val_log_time in column 8

        new_row_data[9] = time.strftime("%Y-%m-%d %H:%M", time.localtime(time_val_log))
        if time_val_log == 0:

            new_row_data[9] = "No log"

        new_row_data += [rtf_link,pdf_link]

        return new_row_data

    #######################################################################################
    ##########################获取所有生成的PDF及RTF#########################################
    ##########################下一步要根据文档时间与log比较取最大值###########################
    #######################################################################################
    def getFileName(self,type):
        #use -4 to remove .pdf or .rtf
        filedir = self.path_init
        path_list = []
        path_list.append(filedir + '/dev/reports/tables')
        path_list.append(filedir + '/dev/reports/figures')
        path_list.append(filedir + '/dev/reports/listings')
        path_list.append(filedir + '/dev/reports/intext')

        file_list = []
        for filedir in path_list:
            temp_list = []
            for root, dirs, files in os.walk(filedir):
                for  filespath in files :
                    if str(filespath).endswith('%s'%type):
                        mtime = os.path.getmtime(os.path.join(root, filespath))
                        file  = filespath[:-4]
                        temp_list.append([file,mtime])
            file_list += temp_list
        return file_list if file_list else []

    #######################################################################################
    #######################################################################################
    ##########################比较文档改动日期，取最大值，保证一个不少########################
    #######################################################################################
    def compTime(self):

        _rtfFiles = self.getFileName('rtf')

        _pdfFiles = self.getFileName('pdf')

        dic_a=dict(_rtfFiles)
        dic_b=dict(_pdfFiles)
        self.rtfFiles = dic_a
        self.pdfFiles = dic_b

        # all1=[]

        # for key in dic_a.keys():
        #     if key in dic_b.keys():
        #         temp=max(dic_a[key],dic_b[key])
        #         all1.append([key,temp])
        #     else:
        #         all1.append([key,dic_a[key]])

        # in_b_not_a = list(set(dic_b.keys()).difference(set(dic_a.keys()))) # b中有而a中没有的

        # for key in in_b_not_a:
        #     all1.append([key,dic_b[key]])

        # return all1 #获取的all1是所有基于RTF_out的最大的日期

    def getTime(self,filePath,type):
        temp_list = []
        for  filename in os.listdir(filePath):
                if str(filename).endswith('%s'%type):
                    mtime = os.path.getmtime(os.path.join(filePath, filename))
                    file  = filename[:-4]
                    temp_list.append([file,mtime])
        return temp_list

    # def dependency(self ):

    #     all_the_final=[]

    #     for row in range(1,self.nrows):

    #         row_data = self.table.row_values(row, start_colx=0, end_colx=None)

    #         # _type               =       row_data[self._type]
    #         # analysis            =       row_data[self.analysis ]
    #         tfl_category        =       row_data[self.tfl_category ]
    #         # population          =       row_data[self.population]
    #         titles              =       row_data[self.titles]
    #         output_number       =       str(row_data[self.output_number])
    #         base_output_name    =       row_data[self.base_output_name]
    #         source_program_name =       row_data[self.source_program_name]
    #         source_data         =       row_data[self.source_data]
    #         source_programmer   =       row_data[self.source_programmer]
    #         qc_programmer       =       row_data[self.qc_programmer]


from torchtext.vocab import Vocab
from torchtext import data
from utils import tokenizer
import os
import pickle

def filter_pred(example):
    if example.label in ['0', '1']:
        if len(example.text) > 1:
            return True
    return False

def get_loader(batch_size=100, max_size=20000, is_train=True, data_dir=None):

    text_field = data.Field(tokenize=tokenizer, sequential=True)
    label_field = data.Field(sequential=False, use_vocab=False, postprocessing=data.Pipeline(int))

    train_file_path = os.path.join(data_dir, 'naver_train.txt')
    test_file_path = os.path.join(data_dir, 'naver_test.txt')

    train_dataset = data.TabularDataset(
        path=train_file_path,
        format='tsv',
        fields=[
            ('id', None),
            ('text', text_field),
            ('label', label_field)
        ],
        filter_pred=filter_pred)

    print('Building Vocabulary \n')
    text_field.build_vocab(train_dataset, max_size=max_size - 2)

    if is_train:
        loader = data.Iterator(
            dataset=train_dataset,
            batch_size=batch_size,
            sort_key=lambda x: len(x.text),
            train=True,  # if training set => repeat and shuffle : True
            repeat=False,
            device=-1  # CPU: -1
        )
    else:
        test_dataset = data.TabularDataset(
            path=test_file_path,
            format='tsv',
            fields=[
                ('id', None),
                ('text', text_field),
                ('label', label_field)
            ],
            filter_pred=filter_pred)

        loader = data.Iterator(
            dataset=test_dataset,
            batch_size=batch_size,
            sort=False,
            train=False,
            device=-1)

    return loader


from collections import defaultdict
import random

class BigramDictionary:

    def __init__(self):
        self.bigram_freq = defaultdict(float)
        self.unique_after_word_cnt = defaultdict(float)
        self.unique_before_word_cnt = defaultdict(float)
        self.unique_bigram_cnt = 0.0

    def update(self, fst_word, snd_word):
        key = fst_word + '_' + snd_word
        if key not in self.bigram_freq:
            self.unique_after_word_cnt[fst_word] += 1.0
            self.unique_before_word_cnt[snd_word] += 1.0
            self.unique_bigram_cnt += 1.0

        self.bigram_freq[key] += 1.0

    def get_bigram_frequency(self, fst_word, snd_word):
        key = fst_word + '_' + snd_word
        if key in self.bigram_freq:
            return self.bigram_freq[key]
        else:
            return 0.0

    def get_next_random_word(self, word):

        word_candidates = []

        for key, value in self.bigram_freq.items():
            if key.startswith(word+'_'):
                word_candidate = key.split('_')[1]

                for i in range(int(value)):
                    word_candidates.append(word_candidate)

        rand_index = random.randint(0, len(word_candidates)-1)
        return word_candidates[rand_index]

    def get_next_most_likely_random_word(self, word):

        max_arg = 0.0
        max_word = '。'

        for key, value in self.bigram_freq.items():
            if key.startswith(word + '_'):

                if value > max_arg:
                    max_arg = value
                    max_word = key.split('_')[1]

        return max_word