#!BPY

"""
Name: 'Sculpteo...'
Blender: 257
Group: 'Export'
Tooltip: 'Upload to Sculpteo'
"""

from builtins import bytes, object

__author__ = "Vivien Chappelier"
__url__ = ["http://www.sculpteo.com"]
__version__ = "1.0"

__bpydoc__ = """\
This script uploads a design on the Sculpteo website.

Usage:

Select the objects you wish to export and run this script from "File->Export" menu.
Selecting the default options from the popup box will be good in most cases.
All objects that can be represented as a mesh (mesh, curve, metaball, surface, text3d) will be exported.
"""

bl_info = {
    "name": "Sculpteo Upload",
    "author": "Vivien Chappelier",
    "version": (1, 0),
    "blender": (2, 5, 5),
    "api": 33333,
    "location": "File > Export > Sculpteo Upload",
    "description": "Upload a Mesh to Sculpteo",
    "warning": "",
    "wiki_url": "",
    "tracker_url": "",
    "category": "Import-Export",
}


import email.generator
import http.cookiejar
import io
import mimetypes
import os
import stat
import tempfile
import urllib.error
import urllib.parse
import urllib.request
import webbrowser
from shutil import rmtree
from uuid import uuid1
from zipfile import ZipFile

import bpy
from io_scene_obj.export_obj import save


# MultipartPostHandler
####
# 02/2006 Will Holcomb <wholcomb@gmail.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
#
class Callable(object):
    def __init__(self, anycallable):
        self.__call__ = anycallable


# Controls how sequences are uncoded. If true, elements may be given
#  multiple values by assigning a sequence.
doseq = 1


class MultipartPostHandler(urllib.request.BaseHandler):
    handler_order = urllib.request.HTTPHandler.handler_order - 10  # needs to run first

    def multipart_encode(self, variables, files, boundary=None, buffer=None):
        if boundary is None:
            boundary = email.generator._make_boundary()
        bboundary = bytes(boundary.encode("utf-8"))
        if buffer is None:
            buffer = b""
        for (key, value) in variables:
            buffer += b"--" + bboundary + b"\r\n"
            buffer += (
                b'Content-Disposition: form-data; name="'
                + bytes(key.encode("utf-8"))
                + b'"'
            )
            buffer += b"\r\n\r\n" + bytes(value.encode("utf-8")) + b"\r\n"
        for (key, fd) in files:
            file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
            filename = os.path.basename(fd.name)
            contenttype = (
                mimetypes.guess_type(filename)[0] or "application/octet-stream"
            )
            buffer += b"--" + bboundary + b"\r\n"
            buffer += (
                b'Content-Disposition: form-data; name="'
                + bytes(key.encode("utf-8"))
                + b'"; filename="'
                + bytes(filename.encode("utf-8"))
                + b'"\r\n'
            )
            buffer += b"Content-Type: " + bytes(contenttype.encode("utf-8")) + b"\r\n"
            # buffer += 'Content-Length: %s\r\n' % file_size
            fd.seek(0)
            buffer += b"\r\n" + fd.read() + b"\r\n"
        buffer += b"--" + bboundary + b"--\r\n\r\n"
        return boundary, buffer

    def http_request(self, request):
        data = request.get_data()
        if data is not None and type(data) != str:
            v_files = []
            v_vars = []
            # try:
            for (key, value) in list(data.items()):
                if isinstance(value, io.IOBase):
                    v_files.append((key, value))
                else:
                    v_vars.append((key, value))
            # except TypeError:
            #    systype, value, traceback = sys.exc_info()
            #    raise TypeError, "not a valid non-string sequence or mapping object", traceback

            if len(v_files) == 0:
                data = urllib.parse.urlencode(v_vars, doseq)
            else:
                boundary, data = self.multipart_encode(v_vars, v_files)
                contenttype = "multipart/form-data; boundary=%s" % boundary
                # if(request.has_header('Content-Type')
                #   and request.get_header('Content-Type').find('multipart/form-data') != 0):
                #    print "Replacing %s with %s" % (request.get_header('content-type'), 'multipart/form-data')
                request.add_unredirected_header("Content-Type", contenttype)

            request.add_data(data)
        return request

    https_request = http_request


cookies = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(
    urllib.request.HTTPCookieProcessor(cookies), MultipartPostHandler
)
urllib.request.install_opener(opener)

# upload
####

SCULPTEO_SERVER = "http://www.sculpteo.com"
# SCULPTEO_SERVER = 'http://localhost:8000'
SCULPTEO_UPLOADFILE = "gallery/uploadfile"
SCULPTEO_UPLOAD = "gallery/3D/upload"


def post_design(filename, name, server, lang="en"):
    uuid = uuid1().int

    # post the file
    upload_post = {"file": open(filename, "rb")}
    upload_url = "%s/%s/%s/?X-Progress-ID=%s" % (
        server,
        lang,
        SCULPTEO_UPLOADFILE,
        uuid,
    )

    # print 'POST %s arg %s' % (upload_url, upload_post)
    page = urllib.request.urlopen(upload_url, upload_post)

    # redirect to upload page to add name, description, etc...
    webbrowser.open_new(
        "%s/%s/%s/?X-Progress-ID=%s&name=%s"
        % (server, lang, SCULPTEO_UPLOAD, uuid, name)
    )


class SCULPTEO_export(bpy.types.Operator):
    """Add a Mesh Object"""

    bl_idname = "sculpteo.upload"
    bl_label = "Upload to Sculpteo"
    bl_description = "Upload a Mesh to Sculpteo"
    bl_options = {"REGISTER", "UNDO"}

    def execute(self, context):

        self.upload_object(context)

        return {"FINISHED"}

    def upload_object(self, context):
        scenename = bpy.context.scene.name

        # export to obj
        filename = "upload.obj"
        subdir = tempfile.mkdtemp()
        try:
            tmpfile = os.path.join(subdir, filename)

            save(None, bpy.context, tmpfile, use_nurbs=False)

            # zip the directory
            zipfd, zipfilename = tempfile.mkstemp(".zip")
            try:
                zipfile = ZipFile(zipfilename, mode="w")
                for name in os.listdir(subdir):
                    zipfile.write(os.path.join(subdir, name), arcname=name)
                zipfile.close()
                os.close(zipfd)

                # send it
                post_design(zipfilename, scenename, SCULPTEO_SERVER)
            finally:
                os.unlink(zipfilename)
        finally:
            rmtree(subdir)


# Registration


def add_object_button(self, context):
    self.layout.operator(SCULPTEO_export.bl_idname, text="Upload to Sculpteo")


def register():
    bpy.utils.register_class(SCULPTEO_export)
    bpy.types.INFO_MT_file_export.append(add_object_button)


def unregister():
    bpy.utils.unregister_class(SCULPTEO_export)
    bpy.types.INFO_MT_file_export.remove(add_object_button)


if __name__ == "__main__":
    register()
