#!/usr/bin/env python
# coding:utf-8
#
import requests
import sys

BASE_URL = "http://api.bayfiles.com/v1"


class FileBasicException(requests.ConnectionError):
    """Exception """
    pass


class FileUploadException(FileBasicException):
    """Exception triggered in upload() method."""
    pass


class FileDeleteException(FileBasicException):
    """Exception triggered in delete() method."""
    pass


class File(object):
    """
    File instance represents the file to send to bayfiles.com.

    Keywords arguments:
    filepath -- the file to upload to bayfiles.com
    account -- a bayfiles.Account instance
    """

    def __init__(self, filepath, account=None):
        self.metadata = {}
        self.filepath = filepath
        self.account = account

        # ask for an upload URL
        self.__register_url()

    def __register_url(self):
        """
        This function will request an upload url to post the file you need to
        store and a progress url that can be polled to know the progress of the
        upload.
        """

        url = BASE_URL + '/file/uploadUrl'
        if self.account and hasattr(self.account, "session"):
            url += '?session={0}'.format(self.account.session)
        request = requests.get(url)

        if not request.ok:
            request.raise_for_status()

        self.metadata = request.json()

        if self.metadata['error'] != u'':
            raise FileUploadException(self.metadata['error'])

    def __get_sha1hash(self):
        """Return the sha1 hash on the entire content of the file passed."""

        # Don't know if it's "right" to import a module in a function
        import hashlib

        sha1_obj = hashlib.sha1()
        with open(self.filepath, 'rb') as file_r:
            while True:
                buffr = file_r.read(0x100000)
                if not buffr:
                    break
                sha1_obj.update(buffr)

        sha1hash = sha1_obj.hexdigest()
        return sha1hash

    def upload(self, validate=True):
        """Upload the file to bayfiles server.

        Keywords arguments:
        validate -- a boolean, if set to True, it will ensure there was no
        corruption during the transfert by comparing the sha1 hash of the local
        file and the one computed by bayfile.

        """
        with open(self.filepath, 'rb') as file_fd:
            files = {'file': file_fd}
            request = requests.post(self.metadata['uploadUrl'], files=files)

        if not request.ok:
            request.raise_for_status()

        json = request.json()
        if json['error'] == '':
            self.metadata.update(json)
        else:
            raise FileUploadException(json['error'])

        # If we ask the sha1 hash validation
        if validate:
            sha1hash = self.__get_sha1hash()
            if not self.metadata['sha1'] == sha1hash:
                raise FileUploadException(
                    "The file was corrupted during the upload")

    def delete(self):
        """Delete the download url and the file stored in bayfiles."""
        url = BASE_URL +\
            '/file/delete/{0}/{1}'.format(self.metadata['fileId'],
                                          self.metadata['deleteToken'])
        try:
            request = requests.get(url)

            if not request.ok:
                request.raise_for_status()

            json = request.json()
            if json['error'] == u'':
                return
            else:
                raise FileDeleteException(json['error'])
        except:
            raise FileDeleteException(sys.exc_info()[0])

    def info(self):
        """Return public information about the file instance."""
        url = BASE_URL +\
            '/file/info/{0}/{1}'.format(self.metadata['fileId'],
                                        self.metadata['infoToken'])
        try:
            request = requests.get(url)

            if not request.ok:
                request.raise_for_status()
            return request.json()

        except AttributeError:
            print "Need to use upload() before info()"
