#
#		Python GUI - File references and types - Generic
#
#		Classes for dealing with file references and file types
#		in as platform-independent a manner as possible.
#
#		In this view of things, a file reference consists
#		of two parts:
#
#			 1) A directory reference, whose nature is
#					platform-dependent,
#
#			 2) A name.
#

import os
from Properties import Properties, overridable_property

class FileRef(Properties):
    """A FileRef represents a file system object in a platform-independent way.
    It consists of two parts, a directory specification and the name of an
    object within that directory. The directory specification always refers
    to an existing directory, but the named object may or may not exist.
    
    Constructors:
        FileRef(dir = DirRef or path, name = string)
        FileRef(path = string)
    """

    dir = overridable_property('dir', "DirRef representing the parent directory.")
    name = overridable_property('name', "Name of the object within the parent directory.")
    path = overridable_property('path', "Full pathname of the object.")

    _dir = None		# DirRef representing the parent directory
    _name = None	# Name, including type suffix if any
    
    #
    #   Constructor
    #
    
    def __init__(self, dir = None, name = None, path = None):
        if dir and name and not path:
            if not isinstance(dir, DirRef):
                dir = DirRef(dir)
        elif path and not (dir or name):
            dirpath, name = os.path.split(path)
            dir = DirRef(path = dirpath)
        else:
            raise TypeError("Invalid argument combination to FileRef constructor")
        self._dir = dir
        self._name = name

    #
    #		Properties
    #

    def get_dir(self):
        return self._dir

    def get_name(self):
        "Return the name of the file."
        return self._name

    def get_path(self):
        return os.path.join(self._dir.path, self._name)

    #
    #		Methods
    #

    def open(self, mode, file_type = None):
        """Open as a file with the given mode and return a file object. On
        platforms which have file-type metadata (e.g. Macintosh), if the
        mode contains 'w' and a file_type is specified, the newly-created
        file will be given the specified type."""
        f = open(self.path, mode)
        if "w" in mode and file_type:
            self._set_type(file_type)
        return f
    
    def mkdir(self):
        """Create a directory with the name and parent directory specified
        by this FileRef. Returns a DirRef for the created directory."""
        return DirRef(os.mkdir(self.path))
    
    def _set_type(self, file_type):
        #  Platforms which have file-type metadata (e.g. Macintosh) use this
        #  to set the type of a file.
        pass

    def __str__(self):
        return "FileRef(%r,%r)" % (self.dir.path, self.name)

#-------------------------------------------------------------------------

class DirRef(Properties):
    """A DirRef is an object representing a directory in the
    file system. Its representation is completely platform
    dependent.
    
    Constructor:
        DirRef(path = string)
    """

    _path = None

    path = overridable_property('path', "Full pathname of the directory.")
    
    def __init__(self, path):
        self._path = path

    def get_path(self):
        return self._path

    def __str__(self):
        return "DirRef(%r)" % self.path

#-------------------------------------------------------------------------

class FileType(Properties):
    """A FileType is a multi-platform representation of a file type."""
    
    _name = None
    _suffix = None
    _mac_creator = None
    _mac_type = None
    _mac_force_suffix = True
    
    name = overridable_property('name', "Human-readable description of the file type")
    suffix = overridable_property('suffix', "Filename suffix (without dot)")
    mac_creator = overridable_property('mac_creator', "Macintosh 4-character creator code")
    mac_type = overridable_property('mac_type', "Macintosh 4-character type code")
    mac_force_suffix = overridable_property('mac_force_suffix', "Enforce filename suffix on MacOSX")
    
    def get_name(self):
        return self._name
    
    def set_name(self, x):
        self._name = x
    
    def get_suffix(self):
        return self._suffix
    
    def set_suffix(self, x):
        self._suffix = x
    
    def get_mac_creator(self):
        return self._mac_creator
    
    def set_mac_creator(self, x):
        self._mac_creator = x

    def get_mac_type(self):
        return self._mac_type
    
    def set_mac_type(self, x):
        self._mac_type = x
    
    def get_mac_force_suffix(self):
        return self._mac_force_suffix
    
    def set_mac_force_suffix(self, x):
        self._mac_force_suffix = x

    def _matches(self, name, mac_type):
        #  Return true if the given name or type code matches that of
        #  this file type.
        this_mac_type = self._mac_type
        this_suffix = self._suffix
        if this_mac_type and mac_type == this_mac_type:
            return True
        #  Allow generic text files to match typeless files for MacOSX
        if not this_suffix and this_mac_type == "TEXT" and mac_type == "\0\0\0\0":
            return True
        if this_suffix and _matches_suffix(name, this_suffix):
            return True
        return False
    
    def _add_suffix(self, name):
        #  Force the given name to have the appropriate suffix for this file
        #  type. Platforms which have other means of representing file types
        #  (e.g. Macintosh) may override this.
        suffix = self._suffix
        if suffix and not _matches_suffix(name, suffix):
            name = "%s.%s" % (name, suffix)
        return name
    
#-------------------------------------------------------------------------

def _matches_suffix(name, suffix):
    #  Test case-insensitively whether the given filename has
    #  the given suffix.
    return name.lower().endswith("." + suffix.lower())
