#
#   Copyright 2016 Red Hat, Inc.
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

import zope
import os
import logging
import json

from imgfac.ImageFactoryException import ImageFactoryException
from imgfac.ApplicationConfiguration import ApplicationConfiguration
from imgfac.CloudDelegate import CloudDelegate

from requests import Session


class AtlasClient(Session):

    default_url = 'https://atlas.hashicorp.com/api/v1'

    def __init__(self, token):
        super(AtlasClient, self).__init__()
        self.headers['X-Atlas-Token'] = token

    def request(self, method, url, **kwargs):
        if url.startswith('/'):
            url = self.default_url + url
        return super(AtlasClient, self).request(method, url, **kwargs)


class Atlas(object):
    """Atlas provider plugin"""
    zope.interface.implements(CloudDelegate)

    def __init__(self):
        super(Atlas, self).__init__()
        self.log = logging.getLogger('%s.%s' % (__name__, self.__class__.__name__))

    def builder_should_create_target_image(self, builder, target, image_id, template, parameters):
        # We are not building target images in this plugin.
        self.log.info('builder_should_create_target_image() called in Atlas plugin')
        return False

    def push_image_to_provider(self, builder, provider, credentials, target, target_image, parameters):
        self.log.info('push_image_to_provider() called in Atlas plugin')

        box = builder.target_image
        image = builder.base_image
        image_format = image.target
        box_format = box.parameters.get('{}_ova_format'.format(image_format))
        self.log.debug('box format {}, disk format {}'.format(box_format, image_format))

        if box.target != 'ova' or not box_format.startswith('vagrant-'):
            raise ImageFactoryException('image {} is not a Vagrant box'.format(box.identifier))

        box_name = parameters.get('atlas_box_name', box.identifier)
        box_version = parameters.get('atlas_box_version', '1.0.0')
        box_provider = box_format[8:]

        keyfile = json.loads(credentials)
        client = AtlasClient(keyfile['token'])
        username = keyfile['username']

        # Create the box if it doesn't exist.

        r = client.get('/box/{0}/{1}'.format(username, box_name))
        if r.status_code == 404:
            new_box = {'box': {'name': box_name, 'username': username}}
            r = client.post('/boxes', json=new_box)
        r.raise_for_status()

        # Create the version if it doesn't exist.

        r = client.get('/box/{0}/{1}/version/{2}'.format(username, box_name, box_version))
        if r.status_code == 404:
            new_version = {'version': {'version': box_version}}
            r = client.post('/box/{0}/{1}/versions'.format(username, box_name), json=new_version)
        r.raise_for_status()

        # Create the provider if it doesn't eixst.

        r = client.get('/box/{0}/{1}/version/{2}/provider/{3}'
                            .format(username, box_name, box_version, box_provider))
        if r.status_code == 404:
            new_provider = {'provider': {'name': box_provider}}
            r = client.post('/box/{0}/{1}/version/{2}/providers'
                                .format(username, box_name, box_version), json=new_provider)
        r.raise_for_status()

        # Now upload the actual data. We use a chunked upload, and it's pretty cool that
        # requests can do that.  Chunking also allows us to keep track of progress.

        r = client.get('/box/{0}/{1}/version/{2}/provider/{3}/upload'
                            .format(username, box_name, box_version, box_provider))
        r.raise_for_status()
        upload = r.json()

        total_size = os.stat(box.data).st_size
        chunksize = 1024*1024  # 1 MiB chunks

        def generate_chunks():
            with open(box.data, 'rb') as fin:
                uploaded = last_percent = 0
                while True:
                    block = fin.read(chunksize)
                    if not block:
                        break
                    yield block
                    uploaded += len(block)
                    percent_complete = int(100 * uploaded / total_size)
                    if percent_complete % 5 == 0 and percent_complete > last_percent:
                        self.log.debug(('upload progress: {0}%'.format(percent_complete)))
                        self.percent_complete = last_percent = percent_complete

        self.status = 'UPLOADING'
        self.percent_complete = 0

        client.put(upload['upload_path'], data=generate_chunks())

        # Release the version.

        client.put('/box/{0}/{1}/version/{2}/release'.format(username, box_name, box_version))

        image_id = '{0}/box/{1}/{2}/version/{3}/provider/{4}' \
                            .format(client.default_url, username, box_name, box_version, box_provider)
        builder.provider_image.identifier_on_provider = image_id
        self.status = 'DONE'
        self.percent_complete = 100

@@ -3347,32 +3347,59 @@
 ise_for_status()
+%0A        version = r.json()
 %0A%0A        # Crea
@@ -4264,935 +4264,302 @@
     
-total_size = os.stat(box.data).st_size%0A        chunksize = 1024*1024  # 1 MiB chunks%0A%0A        def generate_chunks():%0A            with open(box.data, 'rb') as fin:%0A                uploaded = last_percent = 0%0A                while True:%0A                    block = fin.read(chunksize)%0A                    if not block:%0A                        break%0A                    yield block%0A                    uploaded += len(block)%0A                    percent_complete = int(100 * uploaded / total_size)%0A                    if percent_complete %25 5 == 0 and percent_complete %3E last_percent:%0A                        self.log.debug(('upload progress: %7B0%7D%25'.format(percent_complete)))%0A                        self.percent_complete = last_percent = percent_complete%0A%0A        self.status = 'UPLOADING'%0A        self.percent_complete = 0%0A%0A        client.put(upload%5B'upload_path'%5D, data=generate_chunks())%0A%0A        # Release the version.%0A%0A       
+self.status = 'UPLOADING'%0A        self.percent_complete = 0%0A        %0A        with open(box.data, 'rb') as fin:%0A            r = client.put(upload%5B'upload_path'%5D, data=fin)%0A            r.raise_for_status()%0A%0A        # Release the version.%0A%0A        if version%5B'status'%5D != 'active':%0A            r =
  cli
@@ -4641,16 +4641,49 @@
 ersion))
+%0A            r.raise_for_status()
 %0A%0A      

fix upload of provider