"""
$RCSfile: CreationDialog.py,v $

Implements the GUI mini-workflow invoked from the Zope Management
Interface to create an instance of ExternalFile.  This source code has
been factored out of ExternalFile into this separate module for the
reasons listed below:

1. This code is not strictly necessary to use ExternalFile, and in
certain cases (for example, when creating instances programmatically)
one prefers to bypass this code altogether and call the ExternalFile
constructor directly.

2. There are a great many possible error conditions or alternative
scenarios that may occur when creating an instance of ExternalFile TTW
(through the web), resulting in many lines of code.  This code was
threatening to obscure the actual implementation code when it was all
contained in the same module.

3. Zope3 introduces an architecture where GUI handling code and Zope
object implementation code are kept separate and knit together
declaratively through the use of a deployment descriptor.  This allows
alternative GUIs to be plugged in and makes the code much more
general.  For example, it could be used in non-Zope environments.
Creating a separate module for GUI stuff moves us in that direction.

Author: <a href="mailto:cstrong@arielpartners.com">Craeg Strong</a>
Release: 1.2
"""

__cvstag__  = '$Name:  $'[6:-2]
__date__    = '$Date: 2003/04/21 01:52:57 $'[6:-2]
__version__ = '$Revision: 1.8 $'[10:-2]

# Python builtins
from cStringIO import StringIO
import os, socket, string, tempfile

# Zope builtins
from Globals import MessageDialog
from Products.PageTemplates.PageTemplateFile import PageTemplateFile

# Local modules
from FileUtils import copy_file, create_file

# globals() is standard python for passing the current namespace
manage_confirmCreateObjectForm  = PageTemplateFile('www/confirm_create.pt', globals())
manage_conflictCreateObjectForm = PageTemplateFile('www/conflict_create.pt', globals())

def manage_addObjectViaGui(folder,
                           id='', title='', description='',                   # standard
                           target_filepath='', basedir='', upload_file=None,  # externalfile
                           REQUEST=None):
    """
    Workhorse method called from create.pt form.  Actually does the
    work of confirming the user's intended (possibly destructive)
    actions, creating the target file if necessary, and calling
    create_object to actually create the object.  This method may be
    called from create callbacks of derived classes to do the heavy
    lifting.  
    """
    tryagain_url = 'manage_addExternalFileForm'
    action       = REQUEST['action']
    
    if not target_filepath:
        return MessageDialog(title   = 'ERROR',
                             message = 'You must specify a target filepath.',
                             action  = tryagain_url)
    if not id:
        id = target_filepath
        id = id[max(string.rfind(id,'/'), 
                    string.rfind(id,'\\'), 
                    string.rfind(id,':')
                    )+1:]

    # Six possible scenarios:
    #
    # [One]   No upload, target filepath already exists on the server and is readable.
    #         Action: Point to it.
    #
    # [Two]   No upload, target filepath does not exist on the server.
    #         Action: Give option to create blank file or cancel.
    #
    # [Three] No upload, target filepath exists on the server but is not readable.
    #         Action: Display error message, allow user to try again.
    #
    # [Four]  Upload, target filepath does not exist on the server.
    #         Action: Give option to create file with uploaded contents or cancel.
    #
    # [Five]  Upload, target filepath exists on the server but is not writeable.
    #         Action: Display error message, allow user to try again.
    #
    # [Six]   Upload, target filepath exists on the server and is writable.
    #         Action: Give options: overwrite/dont overwrite/try again
    #
    # [Seven] Upload, upload file is empty
    #         Action: Display error message, allow user to try again
    #
    fully_resolved_target_filepath = os.path.join(basedir,target_filepath)

    if not upload_file or not upload_file.filename:
        if not os.path.exists(fully_resolved_target_filepath):
            # Scenario Two
            message= """File %s does not exist yet on server %s.
            Would you like to create a blank file by that name?\n""" % ( fully_resolved_target_filepath,
                                                                         socket.gethostname() )
            return folder.manage_confirmCreateObjectForm(action = action, message = message,
                                                         file_id = id, file_title = title,
                                                         file_description = description,
                                                         basedir = basedir,
                                                         target_filepath = target_filepath,
                                                         temp_filename = '', upload_filename = None)
            try:
                testopen = open(fully_resolved_target_filepath, 'rb')
            except IOError, value:
                # Scenario Three
                message = """Target file %s exists on server %s
                but is not readable (%s).\n""" % (
                    fully_resolved_target_filepath, socket.gethostname(), value )
                message.replace('\n','<br/>')
                return MessageDialog(title   = 'ERROR',
                                     message = message,
                                     action  = tryagain_url)
        else:
            # Scenario One
            return manage_createObject(folder, action, id, title, description,
                                       target_filepath, basedir,
                                       upload_file = None,
                                       REQUEST = REQUEST)
    else:
        #
        # we have an uploaded file.  Grab the contents and store in a
        # temporary file, copy it over to target_pathname iff the user
        # confirms this potentially destructive action
        #
        temp_filename = tempfile.mktemp()
        upload_contents = upload_file.read()
        if not upload_contents:
            message = """Uploaded file %s is empty.
            Please specify a non-empty file.\n""" % upload_file.filename
            message.replace('\n','<br/>')
            return MessageDialog(title   = 'ERROR',
                                 message = message,
                                 action  = tryagain_url)
        else:
            data = StringIO(upload_contents)
            copy_file(data, temp_filename)
            if not os.path.exists(fully_resolved_target_filepath):
                # Scenario Four
                message = """File %s does not exist yet on server %s.
                Would you like to create a file by that name containing the uploaded contents?
                """ % ( fully_resolved_target_filepath, socket.gethostname() )
                return folder.manage_confirmCreateObjectForm(action = action, message = message,
                                                             file_id = id, file_title = title,
                                                             file_description = description,
                                                             basedir = basedir,
                                                             target_filepath = target_filepath,
                                                             temp_filename = temp_filename,
                                                             upload_filename = upload_file.filename)
            else:
                try:
                    testopen = open(fully_resolved_target_filepath, 'ab')
                    testopen.close()
                except IOError, value:
                    # Scenario Five
                    message = """Target file %s is not writable
                    on server %s (%s).\n""" % (
                        fully_resolved_target_filepath, socket.gethostname(), value )
                    message.replace('\n','<br/>')                    
                    return MessageDialog(title   = 'ERROR',
                                         message = message,
                                         action  = tryagain_url)
                else:
                    # Scenario Six
                    return folder.manage_conflictCreateObjectForm(action = action, file_id = id,
                                                                  file_title = title,
                                                                  file_description = description,
                                                                  basedir = basedir,
                                                                  target_filepath = target_filepath,
                                                                  temp_filename = temp_filename,
                                                                  upload_filename = upload_file.filename)

def manage_confirmCreateObject(folder, action,
                               file_id, file_title, file_description,
                               target_filepath, basedir,
                               temp_filename, upload_filename,
                               REQUEST):
    """
    Create a new instance of ExternalFile pointing to target filepath
    on server.  If user has uploaded a file (upload_file is not None),
    overwrite the contents of the server file with the uploaded file
    contents.
    """
    tryagain_url = 'manage_addExternalFileForm'
    fully_resolved_target_filepath = os.path.join(basedir,target_filepath)
    target_is_existing_file = os.path.exists(fully_resolved_target_filepath)
    
    create_msg = ""
    if upload_filename:
        try:
            create_file(temp_filename, fully_resolved_target_filepath)
        except IOError, value:
            message = """Target file %s is not writable
            on server %s (%s).\n""" % (
                fully_resolved_target_filepath, socket.gethostname(), value )
            message.replace('\n','<br/>')
            return MessageDialog(title   = 'ERROR',
                                 message = message,
                                 action  = tryagain_url)
        if target_is_existing_file:
            message = """Object instance %s successfully created,
            pointing to file %s on %s.
            Contents of %s:%s
            were replaced by contents of uploaded file %s.
            File successfully created.\n""" % (
                file_id, fully_resolved_target_filepath, socket.gethostname(),
                socket.gethostname(), fully_resolved_target_filepath,
                upload_filename)
        else:
            message = """Object instance %s successfully created,
            pointing to newly-created file %s on %s,
            with contents copied from uploaded file %s.
            File successfully created.\n""" % (
                file_id, fully_resolved_target_filepath, socket.gethostname(),
                upload_filename )
    else:
        if not target_is_existing_file:
            try:
                create_file(None, fully_resolved_target_filepath)
            except IOError, value:
                message = """Target file %s is not writable
                on server %s (%s).\n""" % (
                    fully_resolved_target_filepath, socket.gethostname(), value)
                message.replace('\n','<br/>')
                return MessageDialog(title   = 'ERROR',
                                     message = message,
                                     action  = tryagain_url)
        message = """Object instance %s successfully created,
        pointing to file %s on %s.
        File successfully created.\n""" % (
            file_id, fully_resolved_target_filepath, socket.gethostname() )

    return manage_createObject(folder, action, file_id, file_title, file_description,
                               target_filepath, basedir, upload_file = None,
                               REQUEST = REQUEST)


# derived classes must create their own version of this function
def manage_createObject(folder, action, id='',
                        title='', description='',
                        target_filepath='', basedir='',
                        upload_file = None,
                        REQUEST=None):
    """
    Factory method to create an instance of ExternalFile, called
    from a GUI in the Zope Management Interface.  It calls
    addExternalFile to actually do the work.
    """
    if type(action) == type([]):
        act = action[0]
    elif type(action) == type(''):
        act = action

    try:
        
        folder.addExternalFile(id, title, description,
                               target_filepath,
                               basedir, upload_file)
        
        if REQUEST is None:
            return

        # support Add and Edit
        try:
            url = folder.DestinationURL()
        except:
            url = REQUEST['URL1']
        if act.find("Edit") != -1:
            url = "%s/%s" % (url, id)
            REQUEST.RESPONSE.redirect(url + '/manage_editForm')
        else:
            REQUEST.RESPONSE.redirect(url + "/manage_main")
        
    except Exception, e:
        message = str(e)
        message.replace('\n','<br/>')
        return MessageDialog(title   = 'Error',
                             message = message,
                             action  = 'manage_main')

# EOF
