import os
from binstar_client import errors


class Downloader(object):
    """
    Download a notebook or a data file from Binstar.org
    """
    def __init__(self, binstar, username, project):
        self.binstar = binstar
        self.username = username
        self.project = project
        self.location = project

    def call(self, basename=None, force=False, output=None):
        if output is not None:
            self.location = output
        self.ensure_location(force)
        if basename is None:
            for f in self.list_files():
                if self.can_download(f, force):
                    self.download(f)
        else:
            dist = next(dist for dist in self.list_files() if dist['basename'] == basename)
            if dist is None:
                raise errors.NotFound(basename)
            if self.can_download(dist, force):
                self.download(dist)
            else:
                raise errors.DestionationPathExists(os.join(self.location), basename)

    def download(self, dist):
        """
        Download file into location
        """
        requests_handle = self.binstar.download(self.username, self.project, dist['version'], dist['basename'])

        with open(os.path.join(self.location, dist['basename']), 'w') as fdout:
            for chunk in requests_handle.iter_content(4096):
                fdout.write(chunk)

    def can_download(self, dist, force=False):
        """
        Can download if location/file does not exist or if force=True
        :param dist:
        :param force:
        :return: True/False
        """
        return not os.path.exists(os.path.join(self.location, dist['basename'])) or force

    def ensure_location(self, force):
        """
        Created directory dir
        """
        if not os.path.exists(self.location):
            os.makedirs(self.location)
        elif not force:
            raise errors.DestionationPathExists(self.location)

    def list_files(self):
        """
        List available files in a project
        :return: list
        """
        output = []
        tmp = {}
        files = self.binstar.package(self.username, self.project)['files']

        for f in files:
            if f['basename'] in tmp:
                tmp[f['basename']].append(f)
            else:
                tmp[f['basename']] = [f]

        for basename, versions in tmp.items():
            output.append(max(versions, key=lambda x: int(x['version'])))

        return output

@@ -525,35 +525,34 @@
     
-for f in self.list
+self.download
 _files(
+force
 )
-:
 %0A   
@@ -552,32 +552,38 @@
 ce)%0A        
+else:%0A
         
 if self.can_
@@ -570,36 +570,33 @@
         
-if
+   
  self.
-can_
 download
 (f, forc
@@ -591,18 +591,30 @@
 load
-(f
+_file(basename
 , force)
 :%0A  
@@ -609,32 +609,56 @@
 , force)
-:
+%0A
 %0A    
-  
+def download(self, dist):%0A
         
       se
@@ -653,30 +653,47 @@
     
+%22%22%22%0A
       
-self.d
+  D
 ownload
-(f)
+ file into location
 %0A   
@@ -689,37 +689,35 @@
 ocation%0A        
-else:
+%22%22%22
 %0A            dis
@@ -713,168 +713,368 @@
     
-    dist = next(dist for dist in self.list_files() if dist%5B'basename'%5D == basename)%0A            if dist is None:%0A                raise errors.NotFound(basename)
+requests_handle = self.binstar.download(self.username, self.project, dist%5B'version'%5D, dist%5B'basename'%5D)%0A%0A        with open(os.path.join(self.location, dist%5B'basename'%5D), 'w') as fdout:%0A            for chunk in requests_handle.iter_content(4096):%0A                fdout.write(chunk)%0A%0A    def download_files(self, force=False):%0A        for f in self.list_files():
 %0A   
@@ -1103,20 +1103,17 @@
 ownload(
-dist
+f
 , force)
@@ -1148,30 +1148,62 @@
 oad(
-dist)%0A            e
+f)%0A%0A    def download_file(self, basename, force=Fa
 lse
+)
 :%0A  
@@ -1212,285 +1212,155 @@
     
-        raise errors.DestionationPathExists(os.join(
+dist = next(dist for dist in 
 self.l
-ocation), basename)%0A%0A    def download(self, dist):%0A        %22%22%22%0A        Download file into location%0A        %22%22%22%0A        requests_handle = self.binstar.download(self.username, self.project, dist%5B'version'%5D, dist%5B'
+ist_files() if dist%5B'basename'%5D == basename)%0A        if dist is None:%0A            raise errors.NotFound(
 basename
 '%5D)%0A
@@ -1347,36 +1347,33 @@
 otFound(basename
-'%5D)%0A
+)
 %0A        with op
@@ -1369,174 +1369,169 @@
     
-with open(os.path.join(self.location, dist%5B'basename'%5D), 'w') as fdout:%0A            for chunk in requests_handle.iter_content(4096):%0A                fdout.write(chunk
+if self.can_download(dist, force):%0A            self.download(dist)%0A        else:%0A            raise errors.DestionationPathExists(os.join(self.location), basename
 )%0A%0A 

Refactor download