diff --git a/app/Archive.py b/app/Archive.py
index 9199317305b1edf524721790281b077f65a9f231..9d1f56b2fd5bb38e1cbb7733da824140ef635e09 100644
--- a/app/Archive.py
+++ b/app/Archive.py
@@ -1,56 +1,33 @@
 #!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
-import os, sys, glob, re, io
-import math, subprocess
+import configparser
+import io
+import json
+import os
+import re
+import sys
 import urllib.request
 import zipfile
-import requests
-import datetime
-import configparser
+from collections import UserDict
 from urllib.parse import urlencode
+from uuid import uuid4
 
-from osgeo import gdal, ogr, osr
 import numpy as np
-from uuid import uuid4
+from osgeo import gdal, ogr, osr
 
-from collections import defaultdict, UserDict
 import app.Outils as Outils
-import app.Constantes as Constantes
 
-id_tuile   = re.compile("T[0-9]+[A-Z]+")
+id_tuile = re.compile("T[0-9]+[A-Z]+")
 date_tuile = re.compile("[SENTINEL.+?_]([0-9]*?)-")
 
-class Archive():
+
+class Archive:
     """
         Classe pour lister, télécharger les archives via site Theia selon un shapefile représentant la zone d'étude.
 
-        :param capteur: Nom du satellite utilisé (ex: Landsat, Sentinel2, ...).
-        :type capteur: Chaîne de caractères
-
-        :param bandes: Bandes à conservées.
-        :type bandes: Chaîne de caractères
-
-        :param niveau: Niveau de traitement voulu.
-        :type niveau: Chaîne de caractères
-
-        :param emprise: Chemin vers le shapefile représentant l'emprise.
-        :type emprise: Chaîne de caractères
-
-        :param zone_etude: Chemin vers le shapefile représentant la zone d'étude.
-        :type zone_etude: Chaîne de caractères
-
-        :param sortie: Chemin du dossier de sortie.
-        :type sortie: Chaîne de caractères
-
-        :param annee_debut: Année à partir de laquelle on cherche les images.
-        :type annee_debut: Entier
-
-        :param annee_fin: Année jusqu'à laquelle on cherche les images.
-        :type annee_fin: Entier
-
-        :param seuil: Seuil maximal d'ennuagement.
-        :type seuil: Entier
+        :param config: Chemin vers le fichier de configuration.
+        :type config: Chaîne de caractères
     """
 
     # def __init__(self, capteur, bandes, niveau, emprise, zone_etude, sortie, annee_debut, annee_fin, seuil):
@@ -61,12 +38,30 @@ class Archive():
 
         self.logger = Outils.Log("log", "Archive")
 
+        self.emprise = None
+        self.liste_tuiles = None
+        self.requete = None
+        self.serveur = None
+        self.resto = None
+        self.capteur = None
+        self.api = None
+        self.dossier_sortie = None
+        self.groupe = None
+        self.extraction = None
+        self.bandes = None
+        self.prefix = None
+        self.extent_img = None
+        self.zone_etude = None
+        self.nuage = None
+        self.seuil_nuage = None
+
         Outils.get_variable(self, config)
 
         self.liste_archive = []
         self.url = ''
 
-    def vector_projection_with_epsg(self, chemin_vecteur, output_path, epsg=32630):
+    @staticmethod
+    def vector_projection_with_epsg(chemin_vecteur, output_path, epsg=32630):
 
         driver = ogr.GetDriverByName('ESRI Shapefile')
 
@@ -84,39 +79,35 @@ class Archive():
         if os.path.exists(vecteur_reproj):
             driver.DeleteDataSource(vecteur_reproj)
 
-        outDataSet = driver.CreateDataSource(vecteur_reproj)
-        outLayer = outDataSet.CreateLayer(layer.GetName(), projection_reference, geom_type=layer.GetLayerDefn().GetGeomType())
+        out_data_set = driver.CreateDataSource(vecteur_reproj)
+        out_layer = out_data_set.CreateLayer(layer.GetName(), projection_reference,
+                                             geom_type=layer.GetLayerDefn().GetGeomType())
 
         # add fields
-        inLayerDefn = layer.GetLayerDefn()
-        for i in range(0, inLayerDefn.GetFieldCount()):
-            fieldDefn = inLayerDefn.GetFieldDefn(i)
-            outLayer.CreateField(fieldDefn)
+        in_layer_defn = layer.GetLayerDefn()
+        for i in range(0, in_layer_defn.GetFieldCount()):
+            field_defn = in_layer_defn.GetFieldDefn(i)
+            out_layer.CreateField(field_defn)
 
-        outLayerDefn = outLayer.GetLayerDefn()
+        out_layer_defn = out_layer.GetLayerDefn()
 
-        inFeature = layer.GetNextFeature()
+        in_feature = layer.GetNextFeature()
 
-        while inFeature:
+        while in_feature:
             # get the input geometry
-            geom = inFeature.GetGeometryRef()
+            geom = in_feature.GetGeometryRef()
             # reproject the geometry
             geom.Transform(transformation)
             # create a new feature
-            outFeature = ogr.Feature(outLayerDefn)
+            out_feature = ogr.Feature(out_layer_defn)
             # set the geometry and attribute
-            outFeature.SetGeometry(geom)
-            for i in range(0, outLayerDefn.GetFieldCount()):
-                outFeature.SetField(outLayerDefn.GetFieldDefn(i).GetNameRef(), inFeature.GetField(i))
+            out_feature.SetGeometry(geom)
+            for i in range(0, out_layer_defn.GetFieldCount()):
+                out_feature.SetField(out_layer_defn.GetFieldDefn(i).GetNameRef(), in_feature.GetField(i))
             # add the feature to the shapefile
-            outLayer.CreateFeature(outFeature)
+            out_layer.CreateFeature(out_feature)
             # dereference the features and get the next input feature
-            outFeature = None
-            inFeature = layer.GetNextFeature()
-
-        # Save and close the shapefiles
-        inDataSet = None
-        outDataSet = None
+            in_feature = layer.GetNextFeature()
 
     def coord_box_dd(self):
         """
@@ -149,72 +140,76 @@ class Archive():
 
         shp_ogr = data_source.GetLayer()
         # Extent
-        extent_ = shp_ogr.GetExtent() # (xMin, xMax, yMin, yMax)
+        extent_ = shp_ogr.GetExtent()  # (xMin, xMax, yMin, yMax)
 
-        ## Close source data
+        # Close source data
         data_source.Destroy()
 
         return "{},{},{},{}".format(extent_[0], extent_[2], extent_[1], extent_[3])
 
     def listing_by_tile(self):
 
-        for tuile in self.liste_tuiles :
-
+        for tuile in self.liste_tuiles:
             self.requete['location'] = tuile
 
-            self.url =  "{0}/{1}/api/collections/{2}/search.json?{3}".format(self.serveur, self.resto, self.capteur, urlencode(self.requete))
+            self.url = "{0}/{1}/api/collections/{2}/search.json?{3}".format(self.serveur, self.resto, self.capteur,
+                                                                            urlencode(self.requete))
 
             self.get_liste_images()
 
     def listing_by_coord(self):
 
         self.requete['box'] = self.coord_box_dd()
-        
-        self.url =  "{0}/{1}/api/collections/{2}/search.json?{3}".format(self.serveur, self.resto, self.capteur, urlencode(self.requete))
-        
+
+        self.url = "{0}/{1}/api/collections/{2}/search.json?{3}".format(self.serveur, self.resto, self.capteur,
+                                                                        urlencode(self.requete))
+
         print(self.url)
 
         self.get_liste_images()
 
     def get_liste_images(self):
-        
+
         # S'il existe une autre image, suivante = vrai, faux sinon
         suivante = True
 
         # Tant qu'il existe une image à traiter
         while suivante:
 
-            try :
+            try:
                 request_headers = {"User-Agent": "Magic-browser"}
-                req = urllib.request.Request(self.url, headers = request_headers) # Connexion à la base de données
-                data = urllib.request.urlopen(req).read() # Lecture de la base de données
+                req = urllib.request.Request(self.url, headers=request_headers)  # Connexion à la base de données
+                data = urllib.request.urlopen(req).read()  # Lecture de la base de données
 
-                new_data = re.sub(b"null", b"'null'", data) # Suppression de l'expression "null" pouvant causer une erreur Python
-                new_data = re.sub(b"false", b"False", new_data) # Renomme le booléen selon la syntaxe Python
+                new_data = re.sub(b"null", b"'null'",
+                                  data)  # Suppression de l'expression "null" pouvant causer une erreur Python
+                new_data = re.sub(b"false", b"False", new_data)  # Renomme le booléen selon la syntaxe Python
 
                 # Conversion des données sous la forme d'un dictionnaire
-                data_Dict = defaultdict(list)
-                data_Dict = UserDict(eval(new_data))
+                # data_Dict = defaultdict(list)
+                data_dict = UserDict(eval(new_data))
 
                 # Selection des archives à télécharger
-                for d in range(len(data_Dict['features'])):
-                    name_archive = data_Dict['features'][d]['properties']['productIdentifier']
-                    feature_id = data_Dict["features"][d]['id']
-                    link_archive = data_Dict['features'][d]['properties']['services']['download']['url'].replace("\\", "")
-                    url_archive = link_archive.replace(self.resto, "rocket/#")
-                    archive_download = url_archive.replace("/download", "") # Url de l'archive à télécharger
-                    out_archive = "{0}/{1}.zip".format(self.dossier_sortie, name_archive) # Nom de sortie de l'archive
+                for d in range(len(data_dict['features'])):
+                    name_archive = data_dict['features'][d]['properties']['productIdentifier']
+                    feature_id = data_dict["features"][d]['id']
+                    # link_archive = data_Dict['features'][d]['properties']['services']['download']['url'].replace("\\",
+                    #                                                                                              "")
+                    # url_archive = link_archive.replace(self.resto, "rocket/#")
+                    # archive_download = url_archive.replace("/download", "") # Url de l'archive à télécharger
+                    out_archive = "{0}/{1}.zip".format(self.dossier_sortie, name_archive)  # Nom de sortie de l'archive
 
                     if "SENTINEL2X" not in out_archive or self.requete["processingLevel"] == "LEVEL3A":
-                        self.liste_archive.append([archive_download, out_archive, feature_id])
+                        # self.liste_archive.append([archive_download, out_archive, feature_id])
+                        self.liste_archive.append([name_archive, feature_id])
 
                 # Vérification si d'autres images sont disponibles
-                for link in data_Dict['properties']['links'] :
-                    if link["title"] is 'suivant' :
+                for link in data_dict['properties']['links']:
+                    if link["title"] is 'suivant':
                         self.url = link['href'].replace("\\", "")
                         suivante = True
                         break
-                    else :
+                    else:
                         suivante = False
 
             except Exception as e:
@@ -228,181 +223,62 @@ class Archive():
 
         if hasattr(self, 'liste_tuiles'):
             self.listing_by_tile()
-        else :
-            self.listing_by_coord()           
+        else:
+            self.listing_by_coord()
 
         self.logger.info("{0} image(s) correspondent aux critères.".format(len(self.liste_archive)))
 
-    def download_auto(self):
+    def download(self):
         """
             Méthode pour télécharger les archives sur le site Theia.
-
-            :param identifiant: Identifant pour le site Theia.
-            :type identifiant: Chaîne de caractères
-
-            :param mdp: Mot de passe pour le site Theia.
-            :type mdp: Chaîne de caractères
-
-            :param proxy: Information du proxy.
-            :type proxy: Chaîne de caractères
         """
 
-        # Url pour obtenir l'authentification
-        url = "{0}/services/authenticate/".format(self.serveur)
-
-   
-        # Dictionnaire contenant les informations du proxy s'il existe
-        proxyDict = {
-            "http"  : "{0}".format(self.proxy), \
-            "https" : "{0}".format(self.proxy), \
-            "ftp"   : "{0}".format(self.proxy) \
-        }
-
-        # Dictionnaire contenant les informations d'authentification
-        payload = {
-            'ident' : "{0}".format(self.id),\
-            'pass' : "{0}".format(self.mdp)
-        }
-
-        # Requête pour obtenir le jeton d'identification
-        reponse = requests.post(url, data=payload, proxies=proxyDict)
-
-        # Récupération du jeton d'identification au format texte ou json
-        try:
-            if "text" in reponse.headers["Content-Type"] :
-                token = reponse.text
-            elif "json" in reponse.headers["Content-Type"] :
-                token = reponse.json()["access_token"]
-            else :
-                raise(BaseException('Format non traité.'))
-        except Exception as e:
-            self.logger.error("Error during the identification request")
-            sys.exit(-1)
-
-        head = {"Authorization": "Bearer {0}".format(token)}
+        dico_date, sauvegarde = self.get_downloadable_images()
 
-        # Dictionnaire des images à traiter regrouper par date
-        dico_date = dict()
+        for date, tuiles in dico_date.items():
+            for img, url in tuiles.items():
+                archive = self.api.get_archive(url)
 
-        sauvegarde = configparser.ConfigParser()
-
-        # Pour toutes les images disponible
-        for l in self.liste_archive :
+                if archive.status_code == 200:
 
-            # Récupération de la date quand l'image a été prise
-            date = date_tuile.search(l[1]).group(1)
-
-            # Récupération du nom de l'image
-            nom_image = l[1].split("/")[-1][:-4]
-
-            # Lecture du fichier de sauvegarde
-            sauvegarde.read("{}/sauvegarde.ini".format(self.dossier_sortie))
-
-            # Si la date existe dans le fichier de sauvegarde ...
-            if str(date) in sauvegarde.keys() :
-
-                # ... mais pas l'image, on la rajoute dans la liste des images à traiter.
-                if nom_image not in sauvegarde[str(date)].keys() :
-
-                    sauvegarde[str(date)][nom_image] = "False"
-
-                    if date in dico_date.keys() :
-                        dico_date[date].append(l)
-                    else :
-                        dico_date[date] = [l]
-
-                # ... et que l'image exite mais n'a pas été traité, on la rajoute dans la liste des images à traiter.
-                elif sauvegarde[str(date)][nom_image] == "False" :
-
-                    if date in dico_date.keys() :
-                        dico_date[date].append(l)
-                    else :
-                        dico_date[date] = [l]
-
-            # Si la date n'existe pas dans le fichier de sauvegarde, on la rajoute ainsi que l'image dans la liste des images à traiter.
-            else :
-                sauvegarde[str(date)] = {}
-                sauvegarde[str(date)][nom_image] = "False"
-
-                if date in dico_date.keys() :
-                    dico_date[date].append(l)
-                else :
-                    dico_date[date] = [l]
-
-            # Sauvegarde du fichier de sauvegarde mis à jour.
-            with open("{}/sauvegarde.ini".format(self.dossier_sortie), 'w') as configfile:
-                sauvegarde.write(configfile)
-
-        # Pour toutes les dates à traiter
-        for cle in sorted(dico_date):
-            # Liste des archives
-            liste_content = []
-
-            # Pour toutes les images prisent à cette date
-            for idx, img in enumerate(dico_date[cle]):
-
-                self.logger.info("Requête pour l'archive : {0}".format(img[1].split("/")[-1]))
-                # Url de l'archive
-                url = "{0}/{1}/collections/{2}/{3}/download/?issuerId=theia".format(self.serveur, self.resto, self.capteur, img[2])
-                self.logger.debug("url : {}".format(url))
-
-                # Requête pour récupérer l'archive
-                reponse = requests.get(url, headers=head, proxies=proxyDict)
-
-                if self.extraction :
-                     # Ajout de l'archive à la liste
-                    liste_content.append(reponse.content)
-                    del reponse
-                else :
-                    if self.groupe == "Tuile" :
-                        dossier_archive = "{0}/{1}".format(self.dossier_sortie, id_tuile.search(img[1]).group(0))
+                    if self.groupe == "Tuile":
+                        output = "{0}/{1}".format(self.dossier_sortie, id_tuile.search(img).group(0))
                     else:
-                        dossier_archive = "{0}/Archive/{1}".format(self.dossier_sortie, cle[:4])
+                        output = "{0}/Archive/{1}".format(self.dossier_sortie, date)
 
-                    if not os.path.exists(dossier_archive):
-                        os.makedirs(dossier_archive)
+                    if not os.path.exists(output):
+                        os.makedirs(output)
 
-                    print("{0}/{1}".format(dossier_archive, img[1].split("/")[-1]))
-                    with open("{0}/{1}".format(dossier_archive, img[1].split("/")[-1]), "wb") as fichier:
-                        fichier.write(reponse.content)
+                    if self.extraction:
+                        self.extraction_archive(archive.content, output)
+                    else:
 
-            if self.extraction :
-                # Traitement des images (fusion, découpage selon la zone d'étude ...)
-                self.traitement_images(cle, liste_content)
-                del liste_content
+                        dst = "{0}/{1}.zip".format(output, img)
 
+                        self.save_archive(archive, dst)
 
-            # Mis à jour du fichier de sauvegarde
-            # Lecture du fichier de sauvegarde
-            sauvegarde.read("{}/sauvegarde.ini".format(self.dossier_sortie))
+                        sauvegarde[date][img]["Telecharge"] = True
 
-            # Pour toutes les images traitées à cette date
-            for img in dico_date[cle] :
-                # Image traitée passe à vrai dans le fichier de sauvegarde
-                sauvegarde[str(cle)][img[1].split("/")[-1][:-4]] = "True"
+                        self.write_save_file(sauvegarde, dossier=self.dossier_sortie)
 
-            # Sauvegarde du fichier de sauvegarde mis à jour.
-            with open("{}/sauvegarde.ini".format(self.dossier_sortie), 'w') as configfile:
-                sauvegarde.write(configfile)
+                else:
+                    print(archive.status_code)
 
         self.logger.info("All images have been downloaded !")
 
     def calcul_ennuagement(self, tuiles_nuage):
 
-        option_warp     = gdal.WarpOptions(format='Mem', cropToCutline=True, outputType=gdal.GDT_Float32,\
-        								   cutlineDSName=self.emprise, dstNodata="NaN")
-        mosaic_nuage    = gdal.Warp("", tuiles_nuage, options=option_warp)
-
-        rows = mosaic_nuage.RasterYSize # Rows number
-        cols = mosaic_nuage.RasterXSize # Columns number
+        option_warp = gdal.WarpOptions(format='Mem', cropToCutline=True, outputType=gdal.GDT_Float32,
+                                       cutlineDSName=self.emprise, dstNodata="NaN")
+        mosaic_nuage = gdal.Warp("", tuiles_nuage, options=option_warp)
 
-        data = mosaic_nuage.GetRasterBand(1).ReadAsArray(0, 0, cols, rows)
+        data = mosaic_nuage.GetRasterBand(1).ReadAsArray()
 
         nombre_pixel_zone = 0
         nombre_pixel_null = 0
         nombre_pixel_non_nuage = 0
 
-        for donnees in data :
+        for donnees in data:
             d = donnees.tolist()
             nombre_pixel_zone += len(d)
             nombre_pixel_null += d.count(-10000) + np.isnan(d).sum()
@@ -412,13 +288,15 @@ class Archive():
 
         del data
 
-        ennuagement = (float(nombre_pixel_non_nuage)/float(nombre_pixel_non_null)) if nombre_pixel_non_null != 0 else 0.0
-        self.logger.debug("Ennuagement : {}%".format(100 - round(ennuagement*100, 2)))
+        ennuagement = (
+                float(nombre_pixel_non_nuage) / float(nombre_pixel_non_null)) if nombre_pixel_non_null != 0 else 0.0
+        self.logger.debug("Ennuagement : {}%".format(100 - round(ennuagement * 100, 2)))
 
         # Computer cloud's percentage with dist (sum of cloud) by sum of the image's extent
         return 1.0 - ennuagement
 
-    def calcul_aire(self, tuiles_image):
+    @staticmethod
+    def calcul_aire(tuiles_image):
         """
             Méthode pour fusionner un ensemble d'images et calculer l'aire de l'image obtenue.
 
@@ -428,20 +306,19 @@ class Archive():
             :returns: Un tuple contenant l'image fusionnée ainsi que son aire.
         """
 
-        option_warp     = gdal.WarpOptions(format='Mem', resampleAlg="lanczos")
-        mosaic_image    = gdal.Warp("", tuiles_image, options=option_warp)
-
-        rows = mosaic_image.RasterYSize # Rows number
-        cols = mosaic_image.RasterXSize # Columns number
+        option_warp = gdal.WarpOptions(format='Mem', resampleAlg="lanczos")
+        mosaic_image = gdal.Warp("", tuiles_image, options=option_warp)
 
-        data        = mosaic_image.GetRasterBand(1).ReadAsArray(0, 0, cols, rows).astype(np.float16)
-        mask_spec   = ~(np.isnan(data) | np.isin(data, [-10000]))
+        data = mosaic_image.GetRasterBand(1).ReadAsArray()
+        mask_spec = ~(np.isnan(data) | np.isin(data, [-10000]))
 
-        area = float((np.sum(mask_spec) * mosaic_image.GetGeoTransform()[1] * abs(mosaic_image.GetGeoTransform()[-1]) )/10000)
+        area = float(
+            (np.sum(mask_spec) * mosaic_image.GetGeoTransform()[1] * abs(mosaic_image.GetGeoTransform()[-1])) / 10000)
 
         return mosaic_image, area
 
-    def ecriture_geotiff(self, dataset, chemin):
+    @staticmethod
+    def ecriture_geotiff(dataset, chemin):
         """
             Méthode pour enregistrer une image au format GTiff.
 
@@ -458,12 +335,26 @@ class Archive():
         outdata.SetGeoTransform(dataset.GetGeoTransform())
         outdata.SetProjection(dataset.GetProjection())
 
-        for band in range(dataset.RasterCount) :
-            data = dataset.GetRasterBand(band + 1).ReadAsArray(0, 0, dataset.RasterXSize, dataset.RasterYSize).astype(np.float32)
+        for band in range(dataset.RasterCount):
+            data = dataset.GetRasterBand(band + 1).ReadAsArray(0, 0, dataset.RasterXSize, dataset.RasterYSize).astype(
+                np.float32)
             outdata.GetRasterBand(band + 1).WriteArray(data, 0, 0)
             outdata.GetRasterBand(band + 1).FlushCache()
 
-        outdata = None
+    def extraction_archive(self, archive, output):
+
+        # Lecture de l'archive
+        tzip = zipfile.ZipFile(io.BytesIO(archive))
+
+        # Liste des fichiers dans l'archive
+        zip_img = tzip.namelist()
+
+        if "ALL" in self.bandes:
+            tzip.extractall(output)
+        else:
+            for band in self.bandes:
+                chemin = self.get_element(zip_img, "{0}_{1}".format(self.prefix, band))
+                tzip.extract(chemin, output)
 
     def traitement_images(self, date, liste_content):
         """
@@ -491,7 +382,7 @@ class Archive():
         self.logger.info("Extraction des images")
 
         # Pour chaque archive
-        for idx, content in enumerate(liste_content) :
+        for idx, content in enumerate(liste_content):
 
             # Lecture de l'archive
             tzip = zipfile.ZipFile(io.BytesIO(content))
@@ -504,12 +395,12 @@ class Archive():
 
             liste_mem = []
             # Pour tous les fichiers dans l'archive
-            for id_ext, extension in enumerate(self.extent_img) :
+            for id_ext, extension in enumerate(self.extent_img):
                 # Si il s'agit d'une bande voulue (R,G,B,PIR)
                 img = [f for f in zip_img if extension in f][0]
 
                 # On charge l'image en mémoire
-                mmap_name = "/vsimem/"+uuid4().hex
+                mmap_name = "/vsimem/" + uuid4().hex
                 liste_mem.append(mmap_name)
                 gdal.FileFromMemBuffer(mmap_name, tzip.read(img))
                 # liste_bandes.append(gdal.Open(mmap_name))
@@ -525,36 +416,32 @@ class Archive():
 
             del image
 
-            if aire > 0.0 :
+            if aire > 0.0:
                 tuiles_image.append(vrt)
 
                 # On libère la mémoire
-                for mmap_name in liste_mem :
+                for mmap_name in liste_mem:
                     gdal.Unlink(mmap_name)
 
                 liste_mem = []
 
-                if self.nuage is not None :
+                if self.nuage is not None:
                     image_nuage = [f for f in zip_img if self.nuage[0] in f][0]
-                    mmap_name = "/vsimem/"+uuid4().hex
+                    mmap_name = "/vsimem/" + uuid4().hex
 
                     gdal.FileFromMemBuffer(mmap_name, tzip.read(image_nuage))
                     liste_mem.append(mmap_name)
                     tuiles_nuage.append(Outils.clip(mmap_name, self.zone_etude))
 
-            for mmap_name in liste_mem :
+            for mmap_name in liste_mem:
                 gdal.Unlink(mmap_name)
 
-            liste_mem = []
-
-            liste_bandes = None
-
             del tzip
             del liste_content[idx]
 
         del liste_content
 
-        if len(tuiles_image) > 0 :
+        if len(tuiles_image) > 0:
 
             if len(tuiles_nuage) == 0 or self.calcul_ennuagement(tuiles_nuage) <= self.seuil_nuage:
 
@@ -568,8 +455,145 @@ class Archive():
                 self.logger.debug("Dossier image : {0}".format(dossier))
 
                 # On effectue une mosaïque des images qu'on découpe selon l'emprise.
-                Outils.clip(tuiles_image, self.emprise, form="GTiff", dst="{0}/{1}.tif".format(dossier,date))
+                Outils.clip(tuiles_image, self.emprise, form="GTiff", dst="{0}/{1}.tif".format(dossier, date))
 
                 del tuiles_nuage
 
             del tuiles_image
+
+    def save_archive(self, archive, dst):
+
+        self.logger.info("Sauvegarde de l'archive : {}".format(dst))
+        with open("{0}".format(dst), "wb") as fichier:
+            fichier.write(archive.content)
+
+    def select_archive(self):
+
+        # Dictionnaire des images à traiter regrouper par date
+        dico_date = dict()
+
+        sauvegarde = configparser.ConfigParser()
+
+        # Lecture du fichier de sauvegarde
+        sauvegarde.read("{}/sauvegarde.ini".format(self.dossier_sortie))
+
+        # Pour toutes les images disponible
+        for liste in self.liste_archive:
+
+            # Récupération de la date quand l'image a été prise
+            date = date_tuile.search(liste[1]).group(1)
+
+            # Récupération du nom de l'image
+            nom_image = liste[1].split("/")[-1][:-4]
+
+            # Si la date existe dans le fichier de sauvegarde ...
+            if str(date) in sauvegarde.keys():
+
+                # ... mais pas l'image, on la rajoute dans la liste des images à traiter.
+                if nom_image not in sauvegarde[str(date)].keys():
+
+                    sauvegarde[str(date)][nom_image] = "False"
+
+                    if date in dico_date.keys():
+                        dico_date[date].append(liste)
+                    else:
+                        dico_date[date] = [liste]
+
+                # ... et que l'image exite mais n'a pas été traité, on la rajoute dans la liste des images à traiter.
+                elif sauvegarde[str(date)][nom_image] == "False":
+
+                    if date in dico_date.keys():
+                        dico_date[date].append(liste)
+                    else:
+                        dico_date[date] = [liste]
+
+            # Si la date n'existe pas dans le fichier de sauvegarde, on la rajoute ainsi que l'image dans la liste
+            # des images à traiter.
+            else:
+                sauvegarde[str(date)] = {}
+                sauvegarde[str(date)][nom_image] = "False"
+
+                if date in dico_date.keys():
+                    dico_date[date].append(liste)
+                else:
+                    dico_date[date] = [liste]
+
+            # Sauvegarde du fichier de sauvegarde mis à jour.
+            with open("{}/sauvegarde.ini".format(self.dossier_sortie), 'w') as configfile:
+                sauvegarde.write(configfile)
+
+    @staticmethod
+    def read_save_file(dossier="", nom="sauvegarde"):
+        if os.path.exists("{0}/{1}.json".format(dossier, nom)):
+            return json.load(open("{0}/{1}.json".format(dossier, nom), "r"))
+        else:
+            return dict()
+
+    def get_downloadable_images(self):
+        dico_date = dict()
+        sauvegarde = self.read_save_file(dossier=self.dossier_sortie)
+
+        # Pour toutes les images disponible
+        for archive, idx in self.liste_archive:
+
+            # Récupération de la date quand l'image a été prise
+            date = date_tuile.search(archive).group(1)
+
+            # Si la date existe dans le fichier de sauvegarde ...
+            if date in sauvegarde.keys():
+
+                # ... mais pas l'image, on la rajoute dans la liste des images à traiter.
+                if archive not in sauvegarde[date].keys():
+
+                    # sauvegarde[date][archive] = False
+                    sauvegarde[date][archive] = dict({"Telecharge": False, "Identifiant": idx})
+
+                    if date in dico_date.keys():
+                        # dico_date[date].append(archive)
+                        dico_date[date][archive] = self.generate_url(idx)
+                    else:
+                        # dico_date[date] = [archive]
+                        dico_date[date] = dict({archive: self.generate_url(idx)})
+
+                # ... et que l'image exite mais n'a pas été traité, on la rajoute dans la liste des images à traiter.
+                elif sauvegarde[date][archive]["Telecharge"] is False:
+
+                    if date in dico_date.keys():
+                        # dico_date[date].append(archive)
+                        dico_date[date][archive] = self.generate_url(idx)
+                    else:
+                        # dico_date[date] = [archive]
+                        dico_date[date] = dict({archive: self.generate_url(idx)})
+
+            # Si la date n'existe pas dans le fichier de sauvegarde, on la rajoute ainsi que l'image dans la liste
+            # des images à traiter.
+            else:
+                sauvegarde[date] = dict()
+                sauvegarde[date][archive] = dict()
+                sauvegarde[date][archive]["Telecharge"] = False
+                sauvegarde[date][archive]["Identifiant"] = idx
+
+                if date in dico_date.keys():
+                    # dico_date[date].append(archive)
+                    dico_date[date][archive] = self.generate_url(idx)
+                else:
+                    # dico_date[date] = [archive]
+                    dico_date[date] = dict({archive: self.generate_url(idx)})
+
+        self.write_save_file(sauvegarde, dossier=self.dossier_sortie)
+
+        return dico_date, sauvegarde
+
+    @staticmethod
+    def write_save_file(dico, dossier="", nom="sauvegarde"):
+        # Sauvegarde du fichier de sauvegarde mis à jour.
+        with open("{0}/{1}.json".format(dossier, nom), 'w') as fichier:
+            json.dump(dico, fichier, indent=4)
+
+    def generate_url(self, idx):
+        return "{0}/{1}/collections/{2}/{3}/download/?issuerId=theia".format(self.serveur, self.resto,
+                                                                             self.capteur, idx)
+
+    @staticmethod
+    def get_element(liste, element):
+        return [x for x in liste if element in x][0]