#!BPY

"""
Name: 'COLLADA (.dae) ...'
Blender: 240
Group: 'Export'
Tooltip: 'Export scene to COLLADA format (.dae)'
"""

__author__ = "Mikael Lagre"
__url__ = ("blender", "elysiun", "Project homepage, http://colladablender.sourceforge.net", "Official Collada site, http://www.collada.org")
__version__ = "0.4"
__bpydoc__ = """
Description:

Exports Blender scene to the COLLADA 1.3.1 format.

Usage: run the script from the menu or inside Blender.  

Notes: the script does not export animations yet.
"""

# --------------------------------------------------------------------------
# Collada exporter version 0.4
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2005: Mikael Lagre' contactme@mikaellagre.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------





_ERROR = False

try:
    import math
except:
    print "Error! Could not find math module"
    _ERROR = True

try:
    import Blender
    from Blender import *
except:
    print "Error! Could not find Blender modules!"
    _ERROR = True
try:
    from xml.dom.minidom import Document, Element, Childless, Text, _write_data
except:
    print "\nError! Could not find XML modules!"
    _ERROR = True

if _ERROR:
    from sys import version_info
    version = '%s.%s' % version_info[0:2]
    print """
This script requires the xml module that is part of a
default standalone Python install.

To run the collada importer and exporter you need to have
Python version %s installed in your system. It can be downloaded from:

http://www.python.org

Notes:
- The minor (third) version number doesn't matter, you can have either
Python %s.1 or %s.2 or higher.
- If you do have Python %s installed and still can't run the scripts, then
make sure Blender's Python interpreter is finding the standalone modules
(run 'System Information' from Blender's Help -> System menu).
""" % (version, version, version, version)
    Draw.PupMenu("Error: missing module(s), please check console")


# === GLOBAL EXPORT SETTINGS ===
exportBakedTransform = True        # Export <matrix> element transform
exportSelected = False              # Export selected objects only
niceFormat = False                  # Creates a more readable document
# ==============================

# Global FPS for animation export (exporter uses render->anim settings)
fps = 25

# ----------------------------------------------
# Class structures
# ----------------------------------------------
class COLLADADocument( Document ):
    """ A COLLADA Document ( DAE - Digital Asset Exangche) """
    __file_ref = None    
    
    def openFile( self, file ):
        self.__file_ref = open( file, "w" )
        return
    
    def buildXML( self ):
        if not ( self.__file_ref == None ):
            self.writexml( self.__file_ref, "", "\t", '\n', "utf-8" )
        return

    def cleanUp( self ):
        self.unlink()
        self.__file_ref.close()
        return
    
    # Definition of create[ColladaElementTypes]
    def createCOLLADAElement( self, version=None ):
        e = _COLLADAElement( version )
        e.ownerDocument = self
        return e

    def createSceneElement( self, id=None, name=None ):
        e = _SceneElement( id, name )
        e.ownerDocument = self
        return e
        
    def createNodeElement( self, name=None, id=None, nodeType=None ):
        e = _NodeElement( name, id, nodeType )
        e.ownerDocument = self
        return e

    def createBoundingBoxElement( self ):
        e = _BoundingBoxElement( )
        e.ownerDocument = self
        return e

    def createCameraElement( self, id=None, name=None ):
        e = _CameraElement( id, name )
        e.ownerDocument = self
        return e

    def createOpticsElement( self ):
        e = _OpticsElement( )
        e.ownerDocument = self
        return e

    def createImagerElement( self ):
        e = _ImagerElement( )
        e.ownerDocument = self
        return e

    def createInstanceElement( self, url ):
        e = _InstanceElement( url )
        e.ownerDocument = self
        return e

    def createLibraryElement( self, type ):
        e = _LibraryElement( type )
        e.ownerDocument = self
        return e
    
    def createAnimationElement( self, id=None, name=None ):
        e = _AnimationElement( id, name )
        e.ownerDocument = self
        return e
    
    def createChannelElement( self, id=None, name=None, source=None, target=None ):
        e = _ChannelElement( id, name, source, target )
        e.ownerDocument = self
        return e

    def createSamplerElement( self, id=None, name=None  ):
        e = _SamplerElement( id, name )
        e.ownerDocument = self
        return e

    def createControllerElement( self ):
        e = _ControllerElement( )
        e.ownerDocument = self
        return e

    def createSkinElement( self ):
        e = _SkinElement( )
        e.ownerDocument = self
        return e

    def createCombinerElement( self ):
        e = _CombinerElement( )
        e.ownerDocument = self
        return e

    def createJointsElement( self ):
        e = _JointsElement( )
        e.ownerDocument = self
        return e

    def createGeometryElement( self, id=None, name=None ):
        e = _GeometryElement( id, name )
        e.ownerDocument = self
        return e

    def createMeshElement( self, id=None, name=None  ):
        e = _MeshElement( id, name )
        e.ownerDocument = self
        return e
   
    def createLinesElement( self ):
        e = _LinesElement( )
        e.ownerDocument = self
        return e

    def createLinestripsElement( self ):
        e = _LinestripsElement( )
        e.ownerDocument = self
        return e

    def createPolygonsElement( self, count=0, material=None ):
        e = _PolygonsElement( count, material )
        e.ownerDocument = self
        return e
    
    def createPElement( self ):
        e = _PElement( )
        e.ownerDocument = self
        return e
    
    def createTrianglesElement( self ):
        e = _TrianglesElement( )
        e.ownerDocument = self
        return e

    def createTrifansElement( self ):
        e = _TrifansElement( )
        e.ownerDocument = self
        return e

    def createTristripsElement( self ):
        e = _TristripsElement( )
        e.ownerDocument = self
        return e

    def createVerticesElement( self, id, name, count ):
        e = _VerticesElement( id, name, count )
        e.ownerDocument = self
        return e

    def createSourceElement( self, id=None, name=None ):
        e = _SourceElement( id, name )
        e.ownerDocument = self
        return e

    def createAccessorElement( self, count=0, source="", id=None, offset=None, stride=None ):
        e = _AccessorElement( count, id, offset, source, stride)
        e.ownerDocument = self
        return e

    def createArrayElement( self ):
        e = _ArrayElement( )
        e.ownerDocument = self
        return e

    def createBoolArrayElement( self ):
        e = _BoolArrayElement( )
        e.ownerDocument = self
        return e

    def createFloatArrayElement( self, count, id=None, name=None, digits=None, 
                                    magnitude=None ):
        e = _FloatArrayElement( count, id, name, digits, magnitude)
        e.ownerDocument = self
        return e

    def createIntArrayElement( self ):
        e = _IntArrayElement( )
        e.ownerDocument = self
        return e

    def createNameArrayElement( self ):
        e = _NameArrayElement( )
        e.ownerDocument = self
        return e

    def createInputElement( self, idx=None, semantic=None, source=None ):
        e = _InputElement( idx, semantic, source )
        e.ownerDocument = self
        return e

    def createMaterialElement( self, id=None, name=None ):
        e = _MaterialElement( id, name )
        e.ownerDocument = self
        return e

    def createShaderElement( self, id=None, name=None ):
        e = _ShaderElement( id, name )
        e.ownerDocument = self
        return e

    def createPassElement( self ):
        e = _PassElement( )
        e.ownerDocument = self
        return e

    def createTechniqueElement( self, profile=None ):
        e = _TechniqueElement( profile )
        e.ownerDocument = self
        return e

    def createImageElement( self, id=None, name=None, height=None, width=None, 
                                depth=None, source=None, format=None ):
        e = _ImageElement( id, name, height, width, depth, source, format )
        e.ownerDocument = self
        return e

    def createLightElement( self, id=None, name=None, type=None ):
        e = _LightElement( id, name, type )
        e.ownerDocument = self
        return e

    def createTextureElement( self, id=None, name=None ):
        e = _TextureElement( id, name,  )
        e.ownerDocument = self
        return e

    def createProgramElement( self, id=None, name=None, url=None ):
        e = _ProgramElement( id, name, url )
        e.ownerDocument = self
        return e

    def createCodeElement( self ):
        e = _CodeElement( )
        e.ownerDocument = self
        return e

    def createEntryElement( self ):
        e = _EntryElement( )
        e.ownerDocument = self
        return e

    def createParamElement( self, id=None, name=None, type=None, flow=None, 
                            semantic=None, sid=None ):
        e = _ParamElement( id, name, type, flow, semantic, sid )
        e.ownerDocument = self
        return e

    def createMatrixElement( self, sid=None ):
        e = _MatrixElement( sid )
        e.ownerDocument = self
        return e

    def createLookAtElement( self ):
        e = _LookAtElement( )
        e.ownerDocument = self
        return e

    def createPerspectiveElement( self ):
        e = _PerspectiveElement( )
        e.ownerDocument = self
        return e

    def createRotateElement( self, sid=None ):
        e = _RotateElement( sid )
        e.ownerDocument = self
        return e

    def createScaleElement( self, sid=None ):
        e = _ScaleElement( sid )
        e.ownerDocument = self
        return e

    def createSkewElement( self ):
        e = _SkewElement( )
        e.ownerDocument = self
        return e

    def createTranslateElement( self, sid=None ):
        e = _TranslateElement( sid )
        e.ownerDocument = self
        return e

    def createAssetElement( self ):
        e = _AssetElement( )
        e.ownerDocument = self
        return e

    def createAuthorElement( self, data=None ):
        e = _AuthorElement( data )
        e.ownerDocument = self
        return e
    
    def createAuthoringToolElement( self, data=None ):
        e = _AuthoringToolElement( data )
        e.ownerDocument = self
        return e

    def createCreatedElement( self, data=None ):
        e = _CreatedElement( data )
        e.ownerDocument = self
        return e

    def createModifiedElement( self, data=None ):
        e = _ModifiedElement( data )
        e.ownerDocument = self
        return e

    def createRevisionElement( self, data=None ):
        e = _RevisionElement( data )
        e.ownerDocument = self
        return e

    def createSourceDataElement( self, data=None ):
        e = _SourceDataElement( data )
        e.ownerDocument = self
        return e

    def createElement( self, data=None ):
        e = _( data )
        e.ownerDocument = self
        return e

    def createCopyrightElement( self, data=None ):
        e = _CopyrightElement( data )
        e.ownerDocument = self
        return e

    def createTitleElement( self, data=None ):
        e = _TitleElement( data )
        e.ownerDocument = self
        return e

    def createSubjectElement( self, data=None ):
        e = _SubjectElement( data )
        e.ownerDocument = self
        return e

    def createKeywordsElement( self, data=None ):
        e = _KeywordsElement( data )
        e.ownerDocument = self
        return e

    def createCommentsElement( self, data=None ):
        e = _CommentsElement( data )
        e.ownerDocument = self
        return e

    def createUnitElement( self, name=None, meter=None ):
        e = _UnitElement( name, meter )
        e.ownerDocument = self
        return e

    def createUpAxisElement( self, data=None ):
        e = _UpAxisElement( data )
        e.ownerDocument = self
        return e


    def createExtraElement( self ):
        e = _ExtraElement( )
        e.ownerDocument = self
        return e


# COLLADA Common Profile constants strings
# ( for COLLADA specification 1.3.1 )
# Also in this collada common profile class is library type constants
# flow types and other xs:NMTOKEN constants definied in the schema
class _CommonProfile:
    
    COMMON = 1
    BLENDER = 2
    
    str = [ "", "COMMON", "BLENDER" ]
    
    class _ParamName:
        A = 1
        AMBIENT = 2
        ANGLE = 3
        ATTENUATION = 4
        ATTENUATION_SCALE = 5
        B = 6
        BOTTOM = 7
        COLOR = 8
        DIFFUSE = 9
        EMISSION = 10
        FALLOFF = 11
        FALLOFF_SCALE = 12
        G = 13
        LEFT = 14
        P = 15
        Q = 16
        R = 17
        REFLECTIVE = 18
        REFLECTIVITY = 19
        RIGHT = 20
        S = 21
        SHININESS = 22
        SPECULAR = 23
        T = 24
        TANGENT_X = 25
        TANGENT_Y = 26
        TANGENT_Z = 27
        TIME = 28
        TOP = 29
        TRANSPARENCY = 30
        TRANSPARENT = 31
        U = 32
        V = 33
        W = 34
        X = 35
        XFOV = 36
        Y = 37
        YFOV = 38
        Z = 39
        ZFAR = 40
        ZNEAR = 41
        MATRIX4X4 = 42  # Not in Common Profile really but here for baked animation param name
        
        str = [ "", "A", "AMBIENT", "ANGLE", "ATTENUATION", 
                "ATTENUATION_SCALE", "B", "BOTTOM", "COLOR", "DIFFUSE",
                "EMISSION", "FALLOFF", "FALLOFF_SCALE", "G", "LEFT",
                "P", "Q", "R", "REFLECTIVE", "REFLECTIVITY", "RIGHT", "S", 
                "SHININESS", "SPECULAR", "T", "TANGENT.X", "TANGENT.Y", 
                "TANGENT.Z", "TIME", "TOP", "TRANSPARENCY", "TRANSPARENT",
                "U", "V", "W", "X", "XFOV", "Y", "YFOV", "Z", "ZFAR", "ZNEAR", "matrix" ]
    
    class _ProgramIDAndURL:
        ANGLE_MAP = 1
        BEZIER = 2
        BSPLINE = 3
        CARDINAL = 4
        CONSTANT = 5
        CUBE_MAP = 6
        FISH_EYE = 7
        HERMITE = 8
        LAMBERT = 9
        LINEAR = 10
        ORTHOGRAPHIC = 11
        PANORAMA = 12
        PERSPECTIVE = 13
        PHONG = 14
        REAR_FISH_EYE = 15
        SPHERICAL = 16
        
        str = [ "", "ANGLE_MAP", "BEZIER", "BSPLINE", "CARDINAL", "CONSTANT",
                "CUBE_MAP", "FISH_EYE", "HERMITE", "LAMBERT", "LINEAR",
                "ORTHOGRAPHIC", "PANORAMA", "PERSPECTIVE", "PHONG",
                "REAR_FISH_EYE", "SPHERICAL" ]

    class _CodeAndEntrySemantic:
        FRAGMENT_PROGRAM = 1
        VERTEX_PROGRAM = 2
    
    class _InputSemantic:
        BIND_SHAPE_NORMAL = 1
        BIND_SHAPE_POSITION = 2
        BINORMAL = 3
        COLOR = 4
        IMAGE = 5
        INPUT = 6
        IN_TANGENT = 7
        INTERPOLATION = 8
        INV_BIND_MATRIX = 9
        JOINT = 10
        JOINTS_AND_WEIGHTS = 11
        NORMAL = 12
        OUTPUT = 13
        OUT_TANGENT = 14
        POSITION = 15
        TANGENT = 16
        TEXCOORD = 17
        TEXTURE = 18
        UV = 19
        VERTEX = 20
        WEIGHT = 21
        
        str = [ "", "BIND_SHAPE_NORMAL", "BIND_SHAPE_POSITION", "BINORMAL",
                "COLOR", "IMAGE", "INPUT", "IN_TANGENT", "INETRPOLATION", 
                "INV_BIND_MATRIX", "JOINT", "JOINTS_AND_WEIGHTS", "NORMAL",
                "OUTPUT", "OUT_TANGENT", "POSITION", "TANGENT", "TEXCOORD",
                "TEXTURE", "UV", "VERTEX", "WEIGHT" ]
    
    class _ChannelAndControllerTarget:
        #( # )[( # )]
        A = 1
        ANGLE = 2
        B = 3
        G = 4
        P = 5
        Q = 6
        R = 7
        S = 8
        T = 9
        TIME = 10
        U = 11
        V = 12
        W = 13
        X = 14
        Y = 15
        Z = 16

    class _LibraryType:
        ANIMATION = 1
        CAMERA = 2
        CODE = 3
        CONTROLLER = 4
        GEOMETRY = 5
        IMAGE = 6
        LIGHT = 7
        MATERIAL = 8
        PROGRAM = 9
        TEXTURE = 10
        
        str = [ "", "ANIMATION", "CAMERA", "CODE", "CONTROLLER", "GEOMETRY",
                "IMAGE", "LIGHT", "MATERIAL", "PROGRAM", "TEXTURE" ]
    
    
    class _FlowType:
        IN = 1
        OUT = 2
        INOUT = 3
        
        str = [ "", "IN", "OUT", "INOUT" ]

    class _NodeType:
        NODE = 1
        JOINT = 2
        
        str = [ "", "NODE", "JOINT" ]

    class _LightType:
        AMBIENT = 1
        DIRECTIONAL = 2
        POINT = 3
        SPOT = 4
        
        str = [ "", "AMBIENT", "DIRECTIONAL", "POINT", "SPOT" ]
        
    
    # Definition of modules for easier access in code
    # Note: This is pretty stupid I know ...
    
    class PN( _ParamName ):
        pass
    class PIAU( _ProgramIDAndURL ):
        pass
    class CAES( _CodeAndEntrySemantic ):
        pass
    class IS( _InputSemantic ):
        pass
    class CACT( _ChannelAndControllerTarget ):
        pass
    class LT( _LibraryType ):
        pass
    class FT( _FlowType ):
        pass
    class NT( _NodeType ):
        pass
    class LIGHT( _LightType ):
        pass

# Common Profile
class CP( _CommonProfile ):
    pass


# Element types
# Note that attributes are local here defined as their types (string, float)
# and not Attr object types. Every element
# has defined set and get methods for their types to create a better interface
# for its element type

# NOTE: Do not create instances of these class directly. Use the create...
# functions in COLLADADocument

class _COLLADAElement( Element ):
    
    __version = "1.3.1"
    __xmlns = "http://www.collada.org/2005/COLLADASchema"
    __xmlbase = None
    
    def setVersion( self, version ):
        self.__version = version
        self.setAttribute( "version", self.__version )
        return
    
    def getVersion( self ):
        return self.__version
   
    def __init__( self, version=None ):
        Element.__init__( self, "COLLADA" )
        self.__version = version
        if ( self.__version == None ):
            self.__version = "1.3.1"
        self.setAttribute( "version", self.__version )
        self.setAttribute( "xmlns", self.__xmlns )

class _SceneElement( Element ):
    
    _name = ""
    _id = ""
    
    def __init__( self, id, name ):
        Element.__init__( self, "scene" )
        self._id = id
        self._name = name
        if not ( self._id == None ):
            self.setAttribute( "id", id )
        if not ( self._name == None ):
            self.setAttribute( "name", name )
    
class _NodeElement( Element ):
    
    _name = None
    _id = None
    _nodeType = None
    
    def __init__( self, name, id, nodeType ):
        Element.__init__( self, "node" )
        self._id = id
        self._name = name
        self._nodeType = nodeType
        if not ( self._id == None ):
            self.setAttribute( "id", id )
        if not ( self._name == None ):
            self.setAttribute( "name", name )
        if not ( self._nodeType == None ):
            self.setAttribute( "type", CP.NT.str[ self._nodeType ] )

class _BoundingBoxElement( Element ):
    pass

class _CameraElement( Element ):
    
    _name = ""
    _id = ""
    
    def __init__( self, id, name ):
        Element.__init__( self, "camera" )
        self._id = id
        self._name = name
        if not ( self._id == None ):
            self.setAttribute( "id", id )
        if not ( self._name == None ):
            self.setAttribute( "name", name )

class _OpticsElement( Element) :
    
    def __init__( self ):
        Element.__init__( self, "optics" )


class _ImagerElement( Element ):
    pass

class _InstanceElement( Element, Childless ):
    
    _url = None
    
    def __init__( self, url ):
        Element.__init__( self, "instance" )
        self._url = url
        if not ( self._url == None ):
            self.setAttribute( "url", "#" + self._url )

class _LibraryElement( Element ):

    _libraryType = None
    _name = None
    _id = None
    
    def __init__( self, libraryType ):
        Element.__init__( self, "library" )
        self._libraryType = libraryType
        self.setAttribute( "type", CP.LT.str[ self._libraryType ] )
    

class _AnimationElement( Element ):
    
    _name = None
    _id = None

    def __init__( self, id, name ):
        Element.__init__( self, "animation" )
        self._id = id
        self._name = name
        if not ( self._id == None ):
            self.setAttribute( "id", id )
        if not ( self._name == None ):
            self.setAttribute( "name", name )

class _ChannelElement( Element ):
    
    _name = None
    _id = None
    _source = None
    _target = None
    
    def __init__( self, id, name, source, target ):
        Element.__init__( self, "channel" )
        self._id = id
        self._name = name
        self._source = source
        self._target = target
        if not ( self._id == None ):
            self.setAttribute( "id", self._id )
        if not ( self._name == None ):
            self.setAttribute( "name", self._name )
        if not ( self._source == None ):
            self.setAttribute( "source", '#' + self._source )
        if not ( self._target == None ):
            self.setAttribute( "target", self._target )
            

class _SamplerElement( Element ):
    
    _name = None
    _id = None
    
    def __init__( self, id, name ):
        Element.__init__( self, "sampler" )
        self._id = id
        self._name = name
        if not ( self._id == None ):
            self.setAttribute( "id", self._id )
        if not ( self._name == None ):
            self.setAttribute( "name", self._name )

class _ControllerElement( Element ):
    pass

class _SkinElement( Element ):
    pass

class _CombinerElement( Element ):
    pass

class _JointsElement( Element ):
    pass

class _GeometryElement( Element ):
    
    _name = ""
    _id = ""
    
    def __init__( self, id, name ):
        Element.__init__( self, "geometry" )
        self._id = id
        self._name = name
        if not ( self._id == None ):
            self.setAttribute( "id", id )
        if not ( self._name == None ):
            self.setAttribute( "name", name )

class _MeshElement( Element ):
    
    _name = ""
    _id = ""
    
    def __init__( self, id, name ):
        Element.__init__( self, "mesh" )
        self._id = id
        self._name = name
        if not ( self._id == None ):
            self.setAttribute( "id", id )
        if not ( self._name == None ):
            self.setAttribute( "name", name )

class _LinesElement( Element ):
    pass

class _LinestripsElement( Element ):
    pass

class _PolygonsElement( Element ):
    
    _count = None
    _material = None
    
    def __init__( self, count, material ):
        Element.__init__( self, "polygons" )
        self._count = count        
        self._material = material        
        
        if not ( self._count == None ):
            self.setAttribute( "count", "%i" % self._count )
        if not ( self._material == None ):
            self.setAttribute( "material", "#" + self._material )

class _PElement( Element, Childless ):
    
    _data = None
    
    def setData( self, data ):
        self._data = data
    
    def getData( self, data ):
        return self._data
    
    def __init__( self ):
        Element.__init__( self, "p" )
    
    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) )    

class _TrianglesElement( Element ):
    pass

class _TrifansElement( Element ):
    pass

class _TristripsElement( Element ):
    pass

class _VerticesElement( Element ):
    
    _id = None
    _name = None
    _count = None
    
    def __init__( self, id, name, count ):
        Element.__init__( self, "vertices" )
        self._id = id
        self._name = name
        self._count = count        
        
        if not ( self._id == None ):
            self.setAttribute( "id", self._id )
        if not ( self._name == None ):
            self.setAttribute( "name", self._name )
        if not ( self._count == None ):
            self.setAttribute( "count", "%i" % self._count )


class _SourceElement( Element ):
    
    _id = None
    _name = None
    
    def __init__( self, id, name ):
        Element.__init__( self, "source" )
        self._id = id
        self._name = name
        if not ( self._id == None ):
            self.setAttribute( "id", id )
        if not ( self._name == None ):
            self.setAttribute( "name", name )

class _AccessorElement( Element ):
    
    _count = None
    _id = None
    _offset = None
    _source = None
    _stride = None
    
    def __init__( self, count, id, offset, source, stride ):
        Element.__init__( self, "accessor" )
        self._count = count
        self._id = id
        self._offset = offset
        self._source = source
        self._stride = stride
        if not ( self._count == None ):
            self.setAttribute( "count", "%i" % self._count )
        if not ( self._id == None ):
            self.setAttribute( "id", self._id )        
        if not ( self._offset == None ):
            self.setAttribute( "offset", "%i" % self._offset )
        if not ( self._source == None ):
            self.setAttribute( "source", "#" + self._source )
        if not ( self._stride == None ):
            self.setAttribute( "stride", "%i" % self._stride )


class _ArrayElement( Element ):
    pass

class _BoolArrayElement( Element ):
    pass

class _FloatArrayElement( Element ):
    
    _count = None
    _id = None
    _name = None    
    _digits = None
    _magnitude = None
    _data = None
    _dataType = 'STRING'
    #_fps = 25   

    def setData( self, data ):
        self._data = data
    
    def getData( self, data ):
        return self._data
    
    def setDataType( self, dataType ):
        self._dataType = dataType
    
    def setCount( self, count ):
        self._count = count
        self.setAttribute( "count", "%i" % self._count )
    
    # def setFPS( self, fps ):
    #    self._fps = fps

    def __init__( self, count, id, name, digits, magnitude ):
        Element.__init__( self, "float_array" )
        self._count = count        
        self._id = id
        self._name = name
        self._digits = digits
        self._magnitude = magnitude
        if not ( self._count == None ):
            self.setAttribute( "count", "%i" % self._count )
        if not ( self._id == None ):
            self.setAttribute( "id", self._id )
        if not ( self._name == None ):
            self.setAttribute( "name", self._name )
        if not ( self._digits == None ):
            self.setAttribute( "digits", "%i" % self._digits )
        if not ( self._magnitude == None ):
            self.setAttribute( "magnitude", "%i" % self._magnitude )

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        
        global niceFormat        
        global fps

        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            
            
            # writer.write(">%s%s</%s>%s" % ( self._data, newl + indent, self.tagName, newl ) )
            writer.write( ">" )
            dataString = ''
            if ( self._dataType == 'POSITION' ):
                if ( niceFormat ):
                    for v in self._data:
                        dataString = "\n%.6f %.6f %.6f" % ( v.co[0], v.co[1], v.co[2]  )
                        writer.write( dataString )
                else:
                    v = self._data
                    dataString = "%.6f %.6f %.6f " % ( v[0].co[0], v[0].co[1], v[0].co[2] )
                    writer.write( dataString )
                    size = len( self._data )
                    for i in range( 1, size - 1 ):
                        dataString = "%.6f %.6f %.6f " % ( v[i].co[0], v[i].co[1], v[i].co[2] )
                        writer.write( dataString )
                    dataString = "%.6f %.6f %.6f" % ( v[size-1].co[0], v[size-1].co[1], v[size-1].co[2] )
                    writer.write( dataString )
                    
            elif ( self._dataType == 'NORMAL' ):
                if ( niceFormat ):
                    for n in self._data:
                        dataString = "\n%.6f %.6f %.6f" % ( n[0], n[1], n[2] )
                        writer.write( dataString )
                else:
                    n = self._data
                    dataString = "%.6f %.6f %.6f " % ( n[0][0], n[0][1], n[0][2] )
                    writer.write( dataString )
                    size = len( self._data )
                    for i in range( 1, size - 1 ):
                        dataString = "%.6f %.6f %.6f " % ( n[i][0], n[i][1], n[i][2] )
                        writer.write( dataString )
                    dataString = "%.6f %.6f %.6f" % ( n[size-1][0], n[size-1][1], n[size-1][2] )
                    writer.write( dataString )
            elif ( self._dataType == 'UV' ):
                if ( niceFormat ):
                    for uv in self._data:
                        dataString = "\n%.6f %.6f" % ( uv[0], uv[1] )
                        writer.write( dataString )
                else:
                    uv = self._data
                    dataString = "%.6f %.6f " % ( uv[0][0], uv[0][1] )
                    writer.write( dataString )
                    size = len( self._data )
                    for i in range( 1, size - 1 ):
                        dataString = "%.6f %.6f " % ( uv[i][0], uv[i][1] )
                        writer.write( dataString )
                    dataString = "%.6f %.6f" % ( uv[size-1][0], uv[size-1][1] )
                    writer.write( dataString )
            elif ( self._dataType == 'ANIMATIONINPUT-MATRIX' ):
                if ( niceFormat ):
                    for tValue in self._data:
                        dataString = "\n%.6f" % ( tValue / fps )
                        writer.write( dataString )
                else:
                    tValue = self._data
                    size = len( self._data )
                    if ( size > 1 ):
                        dataString = '%.6f ' % ( tValue[0] / fps )
                        writer.write( dataString )
                        for i in range( 1, size - 1 ):
                            dataString = '%.6f ' % ( tValue[i] / fps )
                            writer.write( dataString )
                    dataString = "%.6f" % ( tValue[size-1] / fps )
                    writer.write( dataString )                       
            elif ( self._dataType == 'ANIMATIONINPUT' ):
                if ( niceFormat ):
                    for tValue in self._data:
                        dataString = "\n%.6f" % ( tValue.pt[0] / fps )
                        writer.write( dataString )
                else:
                    tValue = self._data
                    size = len( self._data )
                    if ( size > 1 ):
                        dataString = '%.6f ' % ( tValue[0].pt[0] / fps )
                        writer.write( dataString )
                        for i in range( 1, size - 1 ):
                            dataString = '%.6f ' % ( tValue[i].pt[0] / fps )
                            writer.write( dataString )
                    dataString = "%.6f" % ( tValue[size-1].pt[0] / fps )
                    writer.write( dataString )
            elif ( self._dataType == 'ANIMATIONOUTPUT-MATRIX' ):
                if ( niceFormat ):
                    dataString = ''
                    for m in self._data:
                        dataString = '\n%.6f %.6f %.6f %.6f\n%.6f %.6f %.6f %.6f\n%.6f %.6f %.6f %.6f\n%.6f %.6f %.6f %.6f' %  ( m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1], m[0][2], m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3] )
                        writer.write( dataString )
                else:
                    m = self._data[ 0 ]
                    dataString = '%.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f ' %  ( m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1], m[0][2], m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3] )
                    writer.write( dataString )
                    size = len( self._data )
                    for i in range( 1, size - 1 ):
                        m = self._data[ i ]
                        dataString = '%.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f ' %  ( m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1], m[0][2], m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3] )                            
                        writer.write( dataString )
                    m = self._data[ size - 1 ]
                    dataString = '%.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f' %  ( m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1], m[0][2], m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3] )
                    writer.write( dataString )            
            elif ( self._dataType == 'ANIMATIONOUTPUT-SHININESS' ):
                if ( niceFormat ):
                    for tValue in self._data:
                        dataString = "\n%.6f" % ( tValue.pt[1] / 4.0 )
                        writer.write( dataString )
                else:
                    tValue = self._data
                    dataString = "%.6f " % ( tValue[0].pt[1]  / 4.0 )
                    writer.write( dataString )
                    size = len( self._data )
                    for i in range( 1, size - 1 ):
                        dataString = '%.6f ' % ( tValue[i].pt[1] / 4.0 )
                        writer.write( dataString )
                    dataString = "%.6f" % ( tValue[size-1].pt[1] / 4.0 )
                    writer.write( dataString )                
            elif ( self._dataType == 'ANIMATIONOUTPUT-ALPHA' ):
                if ( niceFormat ):
                    for tValue in self._data:
                        dataString = "\n%.6f" % ( 1.0 - tValue.pt[1] )
                        writer.write( dataString )
                else:
                    tValue = self._data
                    dataString = "%.6f " % ( 1.0 - tValue[0].pt[1] )
                    writer.write( dataString )
                    size = len( self._data )
                    for i in range( 1, size - 1 ):
                        dataString = '%.6f ' % ( 1.0 - tValue[i].pt[1] )
                        writer.write( dataString )
                    dataString = "%.6f" % ( 1.0 - tValue[size-1].pt[1] )
                    writer.write( dataString ) 
            elif ( self._dataType == 'ANIMATIONOUTPUT-ROTATION' ):
                if ( niceFormat ):
                    for tValue in self._data:
                        dataString = "\n%.6f" % ( tValue.pt[1] * 10.0 )
                        writer.write( dataString )
                else:
                    tValue = self._data
                    dataString = "%.6f " % ( tValue[0].pt[1] * 10.0 )
                    writer.write( dataString )
                    size = len( self._data )
                    for i in range( 1, size - 1 ):
                        dataString = '%.6f ' % ( tValue[i].pt[1] * 10.0 )
                        writer.write( dataString )
                    dataString = "%.6f" % ( tValue[size-1].pt[1] * 10.0 )
                    writer.write( dataString ) 
            elif ( self._dataType == 'ANIMATIONOUTPUT' ):
                if ( niceFormat ):
                    for tValue in self._data:
                        dataString = "\n%.6f" % ( tValue.pt[1] )
                        writer.write( dataString )
                else:
                    tValue = self._data
                    dataString = "%.6f " % ( tValue[0].pt[1] )
                    writer.write( dataString )
                    size = len( self._data )
                    for i in range( 1, size - 1 ):
                        dataString = '%.6f ' % ( tValue[i].pt[1] )
                        writer.write( dataString )
                    dataString = "%.6f" % ( tValue[size-1].pt[1] )
                    writer.write( dataString )
            else:
                # Replace '\n' with '\n + indent + addindent'
                if ( niceFormat ):
                    replaceString = '\n' + indent + addindent
                    self._data = self._data.replace( '\n', replaceString )
                _write_data( writer, self._data )
            
            if ( niceFormat ):
                writer.write("%s</%s>%s" % ( newl + indent, self.tagName, newl ) )
            else:
                writer.write("</%s>%s" % ( self.tagName, newl ) )


class _IntArrayElement( Element ):
    pass

class _NameArrayElement( Element ):
    pass

class _InputElement( Element ):
    
    _idx = None
    _semantic = None
    _source = None
    
    def __init__( self, idx, semantic, source ):
        Element.__init__( self, "input" )
        self._idx = idx
        self._semantic = semantic
        self._source = source
        if not ( self._idx == None ):
            self.setAttribute( "idx", "%i" % (self._idx) )
        if not ( self._semantic == None ):
            self.setAttribute( "semantic", CP.IS.str[ self._semantic ] )
        if not ( self._source == None ):
            self.setAttribute( "source", "#" + self._source )

class _MaterialElement( Element ):
    
    _id = None
    _name = None
    
    def __init__( self, id, name ):
        Element.__init__( self, "material" )
        self._id = id
        self._name = name
        if not ( self._id == None ):
            self.setAttribute( "id", id )
        if not ( self._name == None ):
            self.setAttribute( "name", name )
        

class _ShaderElement( Element ):
    _id = None
    _name = None
    
    def __init__( self, id, name ):
        Element.__init__( self, "shader" )
        self._id = id
        self._name = name
        if not ( self._id == None ):
            self.setAttribute( "id", self._id )
        if not ( self._name == None ):
            self.setAttribute( "id", self._name )

class _PassElement( Element ):
    def __init__( self ):
        Element.__init__( self, "pass" )

class _TechniqueElement( Element ):
    
    _profile = None
    
    def setProfile( self, profile ):
        self._profile = profile
    
    def __init__( self, profile ):
        Element.__init__( self, "technique" )
        self._profile = profile
        if not ( self._profile == None ):
            self.setAttribute( "profile", CP.str[ self._profile ] )

class _ImageElement( Element ):
    
    _id = None
    _name = None
    _height = None
    _width = None
    _depth = None
    _source = None
    _format = None
    
    def setIdAndName( self, arg ):
        _id = arg
        _name = arg
        self.setAttribute( "id", _id )
        self.setAttribute( "name", _name )
    
    def setWidth( self, width ):
        self._width = width
        self.setAttribute( "width", "%i" % (self._width) )
    
    def setHeight( self, height ):
        self._height = height
        self.setAttribute( "height", "%i" % (self._height) )
    
    def setSource( self, source ):
        self._source = source
        self.setAttribute( "source", self._source )

    def __init__( self, id, name, height, width, depth,
                        source, format ):
        Element.__init__( self, "image" )
        
        self._id = id
        self._name = name
        self._height = height
        self._width = width
        self._depth = depth
        self._source = source
        self._format = format
        
        if not ( self._id == None ):
            self.setAttribute( "id", self._id )
        if not ( self._name == None ):
            self.setAttribute( "name", self._name )
        if not ( self._height == None ):
            self.setAttribute( "height", "%i" % self._height )
        if not ( self._width == None ):
            self.setAttribute( "width", "%i" % self._width )
        if not ( self._depth == None ):
            self.setAttribute( "depth", "%i" % self._depth )
        if not ( self._source == None ):
            self.setAttribute( "source", self._source )
        if not ( self._format == None ):
            self.setAttribute( "format", self._format )

class _LightElement( Element ):
    
    _id = None
    _name = None
    _type = None
    
    def __init__( self, id, name, type ):
        Element.__init__( self, "light" )
        self._id = id
        self._name = name
        self._type = type
        
        if not ( self._id == None ):
            self.setAttribute( "id", self._id )
        if not ( self._name == None ):
            self.setAttribute( "name", self._name )
        if not ( self._type == None ):
            self.setAttribute( "type", "%s" % CP.LIGHT.str[ self._type ] )

class _TextureElement( Element ):
    
    _id = None
    _name = None
    
    def __init__( self, id, name ):
        Element.__init__( self, "texture" )
        self._id = id
        self._name = name
        if not ( self._id == None ):
            self.setAttribute( "id", self._id )
        if not ( self._name == None ):
            self.setAttribute( "name", self._name )

class _ProgramElement( Element ):
    
    _id = None
    _name = None
    _url = None
    
    def __init__( self, id, name, url ):
        Element.__init__( self, "program" )
        self._id = id
        self._name = name
        self._url = url
        if not ( self._id == None ):
            self.setAttribute( "id", self._id )
        if not ( self._name == None ):
            self.setAttribute( "name", self._name )
        if not ( self._url == None ):
            self.setAttribute( "url", self._url ) 

class _CodeElement( Element ):
    pass

class _EntryElement( Element ):
    pass

class _ParamElement( Element, Childless ):
    
    _id = None
    _name = None
    _type = None
    _flow = None
    _semantic = None
    _sid = None
    _data = None
    
    def setData( self, data ):
        self._data = data
    
    def getData( self, data ):
        return self._data
    
    def __init__( self, id, name, type, flow, semantic, sid ):
        Element.__init__( self, "param" )
        self._id = id
        self._name = name
        self._type = type
        self._flow = flow
        self._semantic = semantic
        self._sid = sid
        if not ( self._id == None ):
            self.setAttribute( "id", self._id )        
        if not ( self._name == None ):
            self.setAttribute( "name", CP.PN.str[ self._name ] )
        if not ( self._type == None ):
            self.setAttribute( "type", self._type )
        if not ( self._flow == None ):
            self.setAttribute( "flow", CP.FT.str[ self._flow ] )
        if not ( self._semantic == None ):
            self.setAttribute( "semantic", self._semantic )
        if not ( self._sid == None ):
            self.setAttribute( "sid", self._sid )
            

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) )

class _MatrixElement( Element, Childless ):
    
    _sid = None
    _data = None
    
    def setData( self, data ):
        self._data = data
    
    def getData( self, data ):
        return self._data
    
    def __init__( self, sid ):
        Element.__init__( self, "matrix" )
        self._sid = sid
        if not ( self._sid == None ):
            self.setAttribute( "sid", self._sid )

# Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        
        global niceFormat
        
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            # Replace '\n' with '\n + indent + addindent'
            if ( niceFormat ):
                replaceString = '\n' + indent + addindent
                self._data = self._data.replace( '\n', replaceString )
                writer.write(">%s%s</%s>%s" % ( self._data, newl + indent, self.tagName, newl ) )
            else:
                writer.write(">%s</%s>%s" % ( self._data, self.tagName, newl ) )
                

class _LookAtElement( Element ):
    pass

class _PerspectiveElement( Element ):
    pass

class _RotateElement( Element, Childless ):
    
    _sid = None
    _data = None
    
    def setData( self, data ):
        self._data = data
    
    def getData( self, data ):
        return self._data
    
    def __init__( self, sid ):
        Element.__init__( self, "rotate" )
        self._sid = sid
        if not ( self._sid == None ):
            self.setAttribute( "sid", self._sid )

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) )    

class _ScaleElement( Element, Childless ):
    
    _sid = None
    _data = None
    
    def setData( self, data ):
        self._data = data
    
    def getData( self, data ):
        return self._data
    
    def __init__( self, sid ):
        Element.__init__( self, "scale" )
        self._sid = sid
        if not ( self._sid == None ):
            self.setAttribute( "sid", self._sid )

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) )

class _SkewElement( Element ):
    pass

class _TranslateElement( Element, Childless ):
    
    _sid = None
    _data = None
    
    def setData( self, data ):
        self._data = data
    
    def getData( self, data ):
        return self._data
    
    def __init__( self, sid ):
        Element.__init__( self, "translate" )
        self._sid = sid
        if not ( self._sid == None ):
            self.setAttribute( "sid", self._sid )

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) )    
    

class _AuthorElement( Element, Childless ):
    
    _data = ""
    
    def setData( self, data ):
        self._data = data
    
    def getData( self ):
        return self._data

    def __init__( self, data ):
        Element.__init__( self, "author" )
        if not ( data == None ):
            self._data = data

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) )  

class _AuthoringToolElement( Element, Childless ):
    
    _data = ""
    
    def setData( self, data ):
        self._data = data
    
    def getData( self ):
        return self._data

    def __init__( self, data ):
        Element.__init__( self, "authoring_tool" )
        if not ( data == None ):
            self._data = data

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) )  

class _CreatedElement( Element, Childless ):
    
    _data = ""
    
    def setData( self, data ):
        self._data = data
    
    def getData( self ):
        return self._data

    def __init__( self, data ):
        Element.__init__( self, "created" )
        if not ( data == None ):
            self._data = data

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) )  

class _ModifiedElement( Element, Childless ):
    
    _data = ""
    
    def setData( self, data ):
        self._data = data
    
    def getData( self ):
        return self._data

    def __init__( self, data ):
        Element.__init__( self, "modified" )
        if not ( data == None ):
            self._data = data

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) )  

class _RevisionElement( Element, Childless ):
    
    _data = ""
    
    def setData( self, data ):
        self._data = data
    
    def getData( self ):
        return self._data

    def __init__( self, data ):
        Element.__init__( self, "modified" )
        if not ( data == None ):
            self._data = data

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) )  

class _SourceDataElement( Element, Childless ):
    
    _data = None
    
    def setData( self, data ):
        self._data = data
    
    def getData( self ):
        return self._data

    def __init__( self, data ):
        Element.__init__( self, "source_data" )
        if not ( data == None ):
            self._data = data

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            
            # Fast data write
            # writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) )
            writer.write( ">" )
            _write_data( writer, self._data )
            writer.write( "</%s>%s" % (self.tagName, newl ) )

class _CopyrightElement( Element, Childless ):
    
    _data = ""
    
    def setData( self, data ):
        self._data = data
    
    def getData( self ):
        return self._data

    def __init__( self, data ):
        Element.__init__( self, "copyright" )
        if not ( data == None ):
            self._data = data

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) ) 

class _TitleElement( Element, Childless ):
    
    _data = ""
    
    def setData( self, data ):
        self._data = data
    
    def getData( self ):
        return self._data

    def __init__( self, data ):
        Element.__init__( self, "title" )
        if not ( data == None ):
            self._data = data

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) ) 


class _SubjectElement( Element, Childless ):
    
    _data = ""
    
    def setData( self, data ):
        self._data = data
    
    def getData( self ):
        return self._data

    def __init__( self, data ):
        Element.__init__( self, "subject" )
        if not ( data == None ):
            self._data = data

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) ) 

class _KeywordsElement( Element, Childless ):
    
    _data = ""
    
    def setData( self, data ):
        self._data = data
    
    def getData( self ):
        return self._data

    def __init__( self, data ):
        Element.__init__( self, "keywords" )
        if not ( data == None ):
            self._data = data

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) ) 

class _CommentsElement( Element, Childless ):
    
    _data = ""
    
    def setData( self, data ):
        self._data = data
    
    def getData( self ):
        return self._data

    def __init__( self, data ):
        Element.__init__( self, "comments" )
        if not ( data == None ):
            self._data = data

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) ) 

class _UnitElement( Element, Childless ):
    
    _name = None
    _meter = None
    
    def __init__( self, name, meter ):
        Element.__init__( self, "unit" )
        
        self._name = name
        self._meter = meter
        
        if not ( self._name == None ):
            self.setAttribute( "name", self._name )
        if not ( self._meter == None ):
            self.setAttribute( "meter", self._meter )

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")

        writer.write( "/>%s" % newl )

class _UpAxisElement( Element, Childless ):
    
    _data = ""
    
    def setData( self, data ):
        self._data = data
    
    def getData( self ):
        return self._data

    def __init__( self, data ):
        Element.__init__( self, "up_axis" )
        if not ( data == None ):
            self._data = data

    # Overloaded writexml function so we can keep data within one line
    # This implementation was taken from the Python 2.3 minidom impl.
    # of class Element
    def writexml( self, writer, indent="", addindent="", newl="" ):
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data( writer, attrs[a_name].value)
            writer.write("\"")
        if ( self._data == None ):
            writer.write( "/>%s" % newl )
        else:
            writer.write(">%s</%s>%s" % (self._data, self.tagName, newl ) ) 

class _AssetElement( Element ):

    def __init__( self ):
        Element.__init__( self, "asset" )



class _ExtraElement( Element ):
    pass


# ----------------------------------------------
#    Utility functions
# ----------------------------------------------
def toAngle( radians ):
    return ( radians * 180 ) / 3.14159265


""" Return True if IPO curveName applies to a transform """
def isTransformCurve( curveName ):
    if ( curveName == 'LocX' or
         curveName == 'LocY' or
         curveName == 'LocZ' or
         curveName == 'RotX' or
         curveName == 'RotY' or
         curveName == 'RotZ' or
         curveName == 'SizeX' or
         curveName == 'SizeY' or
         curveName == 'SizeZ' ):
        return True
    return False

""" Return True if IPO curveName applies to a translate """
def isTranslateCurve( curveName ):
    if ( curveName == 'LocX' or
         curveName == 'LocY' or
         curveName == 'LocZ' ):
        return True
    return False

""" Return True if IPO curveName applies to a rotation """
def isRotationCurve( curveName ):
    if ( curveName == 'RotX' or
         curveName == 'RotY' or
         curveName == 'RotZ' ):
        return True
    return False

""" Return a COLLADA param element from IPO curve name """
def getParamElementFromCurveName( curveName ):
    
    # Output TIME if no correct output could be found... (yes kind of stupid
    # I know)
    paramOutput = dae.createParamElement( None, CP.PN.TIME, "float", CP.FT.OUT )
    if ( curveName == 'LocX' or curveName == 'SizeX'):
        paramOutput = dae.createParamElement( None, CP.PN.X, "float", CP.FT.OUT )
    elif ( curveName == 'LocY' or curveName == 'SizeY' ):
        paramOutput = dae.createParamElement( None, CP.PN.Y, "float", CP.FT.OUT )
    elif ( curveName == 'LocZ' or curveName == 'SizeZ' ):
        paramOutput = dae.createParamElement( None, CP.PN.Z, "float", CP.FT.OUT )
    elif ( curveName == 'RotX' or curveName == 'RotY' or curveName == 'RotZ' ):
        paramOutput = dae.createParamElement( None, CP.PN.ANGLE, "float", CP.FT.OUT )
    elif ( curveName == 'R' or curveName == 'ColR' or curveName == 'SpecR' or curveName == 'MirR' ):
        paramOutput = dae.createParamElement( None, CP.PN.R, "float", CP.FT.OUT )
    elif ( curveName == 'G' or curveName == 'ColG' or curveName == 'SpecG' or curveName == 'MirG' ):
        paramOutput = dae.createParamElement( None, CP.PN.G, "float", CP.FT.OUT )
    elif ( curveName == 'B' or curveName == 'ColB' or curveName == 'SpecB' or curveName == 'MirB' ):
        paramOutput = dae.createParamElement( None, CP.PN.B, "float", CP.FT.OUT )
    elif ( curveName == 'Alpha' ):
        paramOutput = dae.createParamElement( None, CP.PN.A, "float", CP.FT.OUT ) 
    elif ( curveName == 'Ref' ):
        paramOutput = dae.createParamElement( None, CP.PN.REFLECTIVITY, "float", CP.FT.OUT ) 
    elif ( curveName == 'Hard' ):
        paramOutput = dae.createParamElement( None, CP.PN.SHININESS, "float", CP.FT.OUT ) 
    
    return paramOutput

""" 
    Return a COLLADA Target written 
    according to the Address Syntax specification.
    The sid values (except the Common Profile constants)
    are my own Blender specific values. However they follow
    the Maya plug-in sid transform syntax.
"""
def getTargetNameFromCurveName( curveName ):
    if ( curveName == 'LocX' ):     return 'translate.X'
    elif ( curveName == 'LocY' ):   return 'translate.Y'
    elif ( curveName == 'LocZ' ):   return 'translate.Z'
    elif ( curveName == 'RotX' ):   return 'rotateX.ANGLE'
    elif ( curveName == 'RotY' ):   return 'rotateY.ANGLE'
    elif ( curveName == 'RotZ' ):   return 'rotateZ.ANGLE'
    elif ( curveName == 'SizeX' ):  return 'scale.X'
    elif ( curveName == 'SizeY' ):  return 'scale.Y'
    elif ( curveName == 'SizeZ' ):  return 'scale.Z'
    elif ( curveName == 'R' ):      return 'diffuse.R'
    elif ( curveName == 'G' ):      return 'diffuse.G'
    elif ( curveName == 'B' ):      return 'diffuse.B'
    elif ( curveName == 'Alpha' ):  return 'transparency'
    elif ( curveName == 'SpecR' ):  return 'specular.R'
    elif ( curveName == 'SpecG' ):  return 'specular.G'
    elif ( curveName == 'SpecB' ):  return 'specular.B'
    elif ( curveName == 'MirR' ):   return 'reflective.R'
    elif ( curveName == 'MirR' ):   return 'reflective.G'
    elif ( curveName == 'MirR' ):   return 'reflective.B'
    elif ( curveName == 'Ref' ):    return 'reflectivity'
    elif ( curveName == 'Hard' ):   return 'shininess'
    else:
        return ''
        


# ----------------------------------------------
#    BLENDER to COLLADA helper functions
# ----------------------------------------------

# --- Write mesh information to dae file ---
def writeLight( libraryElement, light ):
    
    lightName = light.getName( )
    lightID = lightName + "-Lib"
    lightType = light.getType( )
    lightFlags = light.getMode( )
    distance = light.getDist( )
    energy = light.getEnergy( )
    quad1 = light.getQuad1( )
    quad2 = light.getQuad2( )

    # Blender LAMP type --> Collada POINT type
    if ( lightType == 0 ):
        lightElement = dae.createLightElement( lightID, lightName, CP.LIGHT.POINT )
        colorParam = dae.createParamElement( None, CP.PN.COLOR, "float3", CP.FT.IN, None, None )
        colorParam.setData( "%.6f %.6f %.6f" % ( light.col[ 0 ], light.col[ 1 ], light.col[ 2 ]  ) )
        attenuationParam = dae.createParamElement( None, CP.PN.ATTENUATION, "token", CP.FT.IN, None, None )
        attenuationScaleParam = dae.createParamElement( None, CP.PN.ATTENUATION_SCALE, "float", CP.FT.IN, None, None )
        
        if ( lightFlags & light.Modes[ 'Quad' ] ):
            attenuationScale = 2.0 / ( quad2 * distance * energy )
            attenuationParam.setData( "QUADRATIC" )
            attenuationScaleParam.setData( "%.6f" % ( attenuationScale ) )
        else:
            attenuationScale = 2.0 / ( distance * energy )
            attenuationParam.setData( "LINEAR" )
            attenuationScaleParam.setData( "%.6f" % ( attenuationScale ) )
        
        lightElement.appendChild( colorParam )
        lightElement.appendChild( attenuationParam )
        lightElement.appendChild( attenuationScaleParam )
        libraryElement.appendChild( lightElement )
    
    # Blender SUN type --> Collada DIRECTIONAL type
    elif ( lightType == 1 ):
        lightElement = dae.createLightElement( lightID, lightName, CP.LIGHT.DIRECTIONAL )
        colorParam = dae.createParamElement( None, CP.PN.COLOR, "float3", CP.FT.IN, None, None )
        colorParam.setData( "%.6f %.6f %.6f" % ( light.col[ 0 ], light.col[ 1 ], light.col[ 2 ]  ) )
                
        lightElement.appendChild( colorParam )
        libraryElement.appendChild( lightElement )
    
    # Blender SPOT type --> Collada SPOT type
    elif ( lightType == 2 ):
        lightElement = dae.createLightElement( lightID, lightName, CP.LIGHT.SPOT )
        colorParam = dae.createParamElement( None, CP.PN.COLOR, "float3", CP.FT.IN, None, None )
        colorParam.setData( "%.6f %.6f %.6f" % ( light.col[ 0 ], light.col[ 1 ], light.col[ 2 ]  ) )
        
        attenuationParam = dae.createParamElement( None, CP.PN.ATTENUATION, "token", CP.FT.IN, None, None )
        attenuationScaleParam = dae.createParamElement( None, CP.PN.ATTENUATION_SCALE, "float", CP.FT.IN, None, None )
        
        # Is this the correct attenuation algorithm?
        if ( lightFlags & light.Modes[ 'Quad' ] ):
            attenuationScale = 2.0 / ( quad2 * distance * energy )
            attenuationParam.setData( "QUADRATIC" )
            attenuationScaleParam.setData( "%.6f" % ( attenuationScale ) )
        else:
            attenuationScale = 2.0 / ( distance * energy )
            attenuationParam.setData( "LINEAR" )
            attenuationScaleParam.setData( "%.6f" % ( attenuationScale ) )
        
        # Export ANGLE, FALLOFF and FALLOFF_SCALE
        angle = light.getSpotSize( )
        angleParam = dae.createParamElement( None, CP.PN.ANGLE, "float", CP.FT.IN, None, None )
        angleParam.setData( "%.6f" % angle )
        
        
        falloff = light.getSpotSize( )
        falloffParam = dae.createParamElement( None, CP.PN.FALLOFF, "token", CP.FT.IN, None, None )
        falloffParam.setData( "LINEAR" )        
        
        falloffScale = light.getSpotBlend( ) * 128.0
        falloffScaleParam = dae.createParamElement( None, CP.PN.FALLOFF_SCALE, "float", CP.FT.IN, None, None )
        falloffScaleParam.setData( "%.6f" % falloffScale )        
        
        lightElement.appendChild( colorParam )
        lightElement.appendChild( attenuationParam )
        lightElement.appendChild( attenuationScaleParam )
        lightElement.appendChild( angleParam )
        lightElement.appendChild( falloffParam )
        lightElement.appendChild( falloffScaleParam )
        libraryElement.appendChild( lightElement )        
    
    elif ( lightType == 3 ):
        lightElement = dae.createLightElement( lightID, lightName, CP.LIGHT.AMBIENT )
        colorParam = dae.createParamElement( None, CP.PN.COLOR, "float3", CP.FT.IN, None, None )
        colorParam.setData( "%.6f %.6f %.6f" % ( light.col[ 0 ], light.col[ 1 ], light.col[ 2 ]  ) )
        lightElement.appendChild( colorParam )
        libraryElement.appendChild( lightElement )
    elif ( lightType == 4 ):
        print "Warning! Export of light type Area not supported! Light will not export."
    elif ( lightType == 5 ):
        print "Warning! Export of light type Photon not supported! Light will not export."


# --- Write mesh information to dae file ---
def writeMesh( libraryElement, mesh ):
    
    meshName = mesh.name
    meshID = mesh.name + "-Lib"
    hasFaceUV = mesh.hasFaceUV()
    nrVerts = len( mesh.verts )
    nrFaces = len( mesh.faces )    
    geometry = dae.createGeometryElement( meshID, meshName )
    meshElement = dae.createMeshElement( )
    posID = meshName + "-Pos"
    normalID = meshName + "-Normal"
    uvID = meshName + "-UV1"
    position = dae.createSourceElement( posID, posID )
    normal = dae.createSourceElement( normalID, normalID )
    uv = dae.createSourceElement( uvID, uvID )
    posArrayID = posID + "-Array"
    noArrayID = normalID + "-Array"
    uvArrayID = uvID + "-Array"
    floatArrayPos = dae.createFloatArrayElement( nrVerts * 3, posArrayID, posArrayID )
    floatArrayNo = dae.createFloatArrayElement( -1, noArrayID, noArrayID )
    floatArrayUV = dae.createFloatArrayElement( -1, uvArrayID, uvArrayID )
    

    # Set elements data as list data for faster output!
    floatArrayPos.setDataType( 'POSITION' )
    floatArrayNo.setDataType( 'NORMAL' )
    floatArrayUV.setDataType( 'UV' )
    
    # Output nice format for vertex data
    # TODO: Make this routine better
    # startTime = sys.time()
    # posDataArray = array('f')
    # posData = ""
##    for v in mesh.verts:
##        #posDataArray.append( v.co[ 0 ] )
##        #posDataArray.append( v.co[ 1 ] )
##        #posDataArray.append( v.co[ 2 ] )
##        posData += "\n%.6f %.6f %.6f" % ( v.co[0], v.co[1], v.co[2] )
    
    posData = mesh.verts
    
    # Get normal and UV data
    #no = ""
    no = []
    #st = ""
    st = []
    nrExclusiveVertices = 0
    nrUVCoords = 0
    faceNr = 0
    for f in mesh.faces:
        nrVert = len( f.v )
        if ( (nrVert == 3) or (nrVert == 4 ) ):
            if ( f.smooth != 0 ):        # If smooth than fetch normal for every vertex in face
                for v2 in f.v:
                    #no += "\n%.6f %.6f %.6f" % ( v2.no[0], v2.no[1], v2.no[2] )
                    no.append( v2.no )
                    nrExclusiveVertices += 1
            elif ( f.smooth == 0 ):
                # FIXME: There is unknown bug here...
                for i in f.v:
                    if ( len( f.no ) > 0 ):
                        #no += "\n%.6f %.6f %.6f" % ( f.no[0], f.no[1], f.no[2] )
                        no.append( f.no )
                    else:
                        print "Warning! Face has no normal. Outputing (0,0,0) as normal instead!"
                        # TODO: Calculate normal instead!
                        #no += "\n%.6f %.6f %.6f" % ( 0.0, 0.0, 0.0 )
                        no.append( [ 0.0, 0.0, 0.0 ] )
                    nrExclusiveVertices += 1
            
            if ( hasFaceUV ):    # Mesh has face UV set so let's export UV coordinates
                for i in range( nrVert ):
                    #st += "\n%.6f %.6f" % ( f.uv[i][0], f.uv[i][1] )
                    st.append( f.uv[i] )
                    nrUVCoords += 1
        else:
            print "Warning: Face in %s" % meshName + " is not a triangle or quad! Face ignored."
    # endTime = sys.time( )
    # print "Getting mesh data time: %.6f" % ( endTime - startTime )
    
    floatArrayNo.setCount( nrExclusiveVertices * 3 )
    floatArrayNo.setData( no )
    floatArrayPos.setData( posData )
    #floatArrayPos.setData( posDataArray.tostring( ) )
    normal.appendChild( floatArrayNo )
    position.appendChild( floatArrayPos )
    
    if ( hasFaceUV ):
        floatArrayUV.setCount( nrUVCoords * 2 )
        floatArrayUV.setData( st )
        uv.appendChild( floatArrayUV )
    
    meshElement.appendChild( position )
    meshElement.appendChild( normal )
   

    # Write COMMON technique elements
    techniquePos = dae.createTechniqueElement( CP.COMMON )
    techniqueNormal = dae.createTechniqueElement( CP.COMMON )
    accessorPos = dae.createAccessorElement( nrExclusiveVertices, posArrayID, posArrayID + "-Accessor", 0, 3 )
    accessorNormal = dae.createAccessorElement( nrExclusiveVertices, noArrayID, noArrayID + "-Accessor", 0 , 3 )
    
    paramPosX = dae.createParamElement( None, CP.PN.X, "float", None )
    paramPosY = dae.createParamElement( None, CP.PN.Y, "float", None )
    paramPosZ = dae.createParamElement( None, CP.PN.Z, "float", None )
    
    paramNoX = dae.createParamElement( None, CP.PN.X, "float", None )
    paramNoY = dae.createParamElement( None, CP.PN.Y, "float", None )
    paramNoZ = dae.createParamElement( None, CP.PN.Z, "float", None )

    accessorPos.appendChild( paramPosX )
    accessorPos.appendChild( paramPosY )
    accessorPos.appendChild( paramPosZ )

    accessorNormal.appendChild( paramNoX )
    accessorNormal.appendChild( paramNoY )
    accessorNormal.appendChild( paramNoZ )


    techniquePos.appendChild( accessorPos )
    position.appendChild( techniquePos )
    techniqueNormal.appendChild( accessorNormal )
    normal.appendChild( techniqueNormal )

    if ( hasFaceUV ):
        meshElement.appendChild( uv )
        techniqueUV = dae.createTechniqueElement( CP.COMMON )
        accessorUV = dae.createAccessorElement( nrUVCoords, uvArrayID, uvArrayID + "-Accessor", 0, 2 )
        
        paramS = dae.createParamElement( None, CP.PN.S, "float", None )
        paramT = dae.createParamElement( None, CP.PN.T, "float", None )
        
        accessorUV.appendChild( paramS )
        accessorUV.appendChild( paramT )
        
        techniqueUV.appendChild( accessorUV )
        uv.appendChild( techniqueUV )


    # Write vertices and polygons information
    verticesName = meshName + "-Vertices"
    vertices = dae.createVerticesElement( verticesName, verticesName, nrExclusiveVertices )
    vInput = dae.createInputElement( None, CP.IS.POSITION, posID )
    
    # TODO: Write UV here if we have sticky vertices. Also write normal data
    # if the whole mesh is smooth
    
    # Write polygon element
    materials = mesh.getMaterials( 1 )
    
    if ( len( materials ) > 1 ):
        print "Warning! Mesh has multiple materials. Will only export the first one"
    
    # TODO: Write polygon element for each material
    material = None
    polygons = None
    if len( materials ) > 0:
        material = materials[ 0 ]
        if ( material != None ):
            materialSource = material.getName( ) + "-Lib"
            polygons = dae.createPolygonsElement( nrFaces, materialSource )
        else:
            polygons = dae.createPolygonsElement( nrFaces )
    else:
        polygons = dae.createPolygonsElement( nrFaces )
    
    # Write input semantics for polygons
    vertexInput = dae.createInputElement( 0, CP.IS.VERTEX, verticesName )
    normalInput = dae.createInputElement( 1, CP.IS.NORMAL, normalID )
    polygons.appendChild( vertexInput )
    polygons.appendChild( normalInput )
    
    if ( hasFaceUV ):
        uvInput = dae.createInputElement( 2, CP.IS.TEXCOORD, uvID )
        polygons.appendChild( uvInput )
    
    
    # Write <p> elements
        # NOTE: index here points to normal and (if present) texcoord index in floatarray
    index = -1
    for f in mesh.faces:
        pData = ""
        nrVertices = len( f.v )
        if ( (nrVertices == 3) or (nrVertices == 4 ) ):
            for v in f.v:
                index += 1
                if ( hasFaceUV ):
                    pData = pData + "%i %i %i" % ( v.index, index, index ) + " "
                else:
                    pData = pData + "%i %i" % ( v.index, index ) + " "
                
            pData = pData.strip()
            p = dae.createPElement( )
            p.setData( pData )
            polygons.appendChild( p )
        
    
    vertices.appendChild( vInput )
    meshElement.appendChild( vertices )
    meshElement.appendChild( polygons )
    geometry.appendChild( meshElement )
    libraryElement.appendChild( geometry )

# Blender to OpenGL materials
# With help from Nathan (Waffler at Elysiun)
def writeMaterial( libraryElement, material ):
    name = material.getName( )
    id = name + "-Lib"
    materialElement = dae.createMaterialElement( id, name )
    
    # Create common phong shader with one phong pass
    shaderElement = dae.createShaderElement( None, name + "-Phong" )
    technique = dae.createTechniqueElement( CP.COMMON )
    
    # Get material data
    col = material.getRGBCol( )
    speccol = material.getSpecCol( )
    spec = material.getSpec( ) * 0.5
    ambient = material.getAmb( )
    emit = material.getEmit( )
    transparency = 1.0 - material.getAlpha( )
    ref = material.getRef( )
    refcol = material.getMirCol()
    shininess = material.getHardness() / 4.0
    # refID = material.getIOR()

    
    mtextures = material.getTextures( )
    passElement = dae.createPassElement( )               

    # TODO: Perhaps add an option to split texture channels into
    # different <pass> elements instead

    # Input semantics for texture channel(s)            
    for mtex in mtextures:
        if not ( mtex == None ):
            texture = mtex.tex
            if ( texture.type == Texture.Types.IMAGE ):
                texSource = texture.getName() + "-Lib"
                input = dae.createInputElement( None, CP.IS.TEXTURE, texSource )
                passElement.appendChild( input )
                
    
    # Appereantly I cannot access the shaders so ... output
    # PHONG for now

    phongProgram = dae.createProgramElement( None, None,
                        CP.PIAU.str[ CP.PIAU.PHONG ] )
    
    # PHONG PARAMS
    colorParam = dae.createParamElement( None, CP.PN.COLOR, "float3", CP.FT.IN, None, 'color' )
    colorParam.setData( "%.6f %.6f %.6f" % ( col[0], col[1], col[2] ) )
    ambientParam = dae.createParamElement( None, CP.PN.AMBIENT, "float3", CP.FT.IN, None, 'ambient' )
    ambientParam.setData( "%.6f %.6f %.6f" % ( ambient * col[0], ambient * col[1], ambient * col[2] ) )                        
    diffuseParam = dae.createParamElement( None, CP.PN.DIFFUSE, "float3", CP.FT.IN, None, 'diffuse' )
    diffuseParam.setData( "%.6f %.6f %.6f" % ( col[0], col[1], col[2] ) )
    #transparencyParam = dae.createParamElement( None, CP.PN.TRANSPARENCY, "float", CP.FT.IN )
    #transparencyParam.setData( "%.6f" % transparency )                        
    specularParam = dae.createParamElement( None, CP.PN.SPECULAR, "float3", CP.FT.IN, None, 'specular' )
    specularParam.setData( "%.6f %.6f %.6f" % ( speccol[0] * spec, speccol[1]  * spec, speccol[2]  * spec ) )
    emissionParam = dae.createParamElement( None, CP.PN.EMISSION, "float3", CP.FT.IN, None, 'emission' )
    emissionParam.setData( "%.6f %.6f %.6f" % ( emit * col[0], emit * col[1], emit * col[2] ) )

    shininessParam = dae.createParamElement( None, CP.PN.SHININESS, "float", CP.FT.IN, None, 'shininess' )
    shininessParam.setData( "%.6f" % ( shininess ) )

    # Output color as transparent color for now
    transparentParam = dae.createParamElement( None, CP.PN.TRANSPARENT, "float", CP.FT.IN, None, 'transparent' )
    transparentParam.setData( "%.6f %.6f %.6f" % ( col[0], col[1], col[2]  ) )                
    transparencyParam = dae.createParamElement( None, CP.PN.TRANSPARENCY, "float", CP.FT.IN, None, 'transparency' )
    transparencyParam.setData( "%.6f" % ( transparency ) )

    
    reflectParam = dae.createParamElement( None, CP.PN.REFLECTIVE, "float3", CP.FT.IN, None, 'reflective' )
    reflectParam.setData( "%.6f %.6f %.6f" % ( refcol[0], refcol[1], refcol[2]  ) )                
    reflectivityParam = dae.createParamElement( None, CP.PN.REFLECTIVITY, "float", CP.FT.IN, None,'reflectivity' )
    reflectivityParam.setData( "%.6f" % ( ref  ) )
    
    # refractiveParam = dae.createParamElement( None, CP.PN.REFRACTIVEINDEX, "float3", CP.FT.IN )
    # refractiveParam.setData( "%.6f %.6f %.6f" % ( refID[0], refID[1], refID[2]  ) )                
    
    # TODO: Output SHININESS here. Perhaps calc from
    # Specular HARDNESS and SPECULARITY (?)
    phongProgram.appendChild( colorParam )
    phongProgram.appendChild( diffuseParam )
    phongProgram.appendChild( ambientParam )                        
    phongProgram.appendChild( transparencyParam )
    phongProgram.appendChild( specularParam )
    phongProgram.appendChild( emissionParam )
    phongProgram.appendChild( shininessParam )
    phongProgram.appendChild( transparentParam ) 
    phongProgram.appendChild( transparencyParam )                
    phongProgram.appendChild( reflectParam )                                   
    phongProgram.appendChild( reflectivityParam )
    # phongProgram.appendChild( refractiveParam )
    passElement.appendChild( phongProgram )
    technique.appendChild( passElement )
    
    
    shaderElement.appendChild( technique )
    materialElement.appendChild( shaderElement )            
    libraryElement.appendChild( materialElement )

# --- Write Image information to dae file ---
def writeImage( libraryElement, image ):
    name = image.getName( )
    id = name + "-Lib"
    imageElement = dae.createImageElement( id, name )

    # Getting the image size seems to generate 
    # python errors sometimes (for some reason)...
    # imageElement.setWidth( image.size[0] )
    # imageElement.setHeight( image.size[1] )
    filename = sys.expandpath( image.getFilename( ) )
    filename = filename.replace( "//", "/" )    
    filename = filename.replace( sys.sep, "/" )
    filename = "file://" + filename
    imageElement.setSource( filename )
    libraryElement.appendChild( imageElement )
    


def writeTexture( libraryElement, texture ):
    name = texture.getName( )
    id = name + "-Lib"
    
    if ( texture.getType() == "Image" ):
        # Create DIFFUSE texture element
        texID = name + "-Lib"
        textureElement = dae.createTextureElement( texID, name )
    
        # TODO: Depending on type here create different params and techniques
        textureParamElement = dae.createParamElement( None, CP.PN.DIFFUSE, "float3", CP.FT.OUT )
        textureElement.appendChild( textureParamElement )
    
        # Create COMMON Technique
        technique = dae.createTechniqueElement( CP.COMMON )
        textureElement.appendChild( technique )
    
        source = texture.getImage( )
        if not ( source == None ):
            sourceName = source.getName( ) + "-Lib"
            input = dae.createInputElement( None, CP.IS.IMAGE, sourceName )
            technique.appendChild( input )
    
        libraryElement.appendChild( textureElement )
    else:
        print "Warning! Texture is not of Image type. Texture not exported!"


""" Write animation information to dae file """
def writeAnimation( libraryElement, ipo, ipoOwner ):

    global fps
    global exportBakedTransform

    ipoName = ipo.getName()
    ipoID = ipoName + "-Lib" 
    curves = ipo.getCurves( )
    animationElement = dae.createAnimationElement( ipoID, ipoName )
    transformInputElement = None
    transformOutputElement = None
    transformSamplerElement = None
    transformChannelElement = None


    # Store information about curves before creating sources
    transformCurves = []
    otherCurves = []

    transformXMin = 10000
    transformXMax = -10000

    # Get curve types
    for curve in curves:
        curveName = curve.getName( )
        if ( exportBakedTransform and isTransformCurve( curveName ) ):
            transformCurves.append( curve )

            # Get control points (keyframes)
            keyFrames = curve.getPoints( )
            nrKeyFrames = len( keyFrames )
    
            # Get the min and max values from this curve

            for keyFrame in keyFrames:
                points = keyFrame.getPoints( )            
                if ( points[ 0 ] < transformXMin ):
                    transformXMin = int( points[ 0 ] )
                if ( points[ 0 ] > transformXMax ):
                    transformXMax = int( points[ 0 ] )
        else:
            otherCurves.append( curve )
        

    # Check for curves...
    nrTransformCurves = len( transformCurves )
    nrOtherCurves = len( otherCurves )
    nrCurves = nrTransformCurves + nrOtherCurves
    if ( nrCurves == 0 ):
        return
    
    # Calculate and Write baked transform sources
    if ( exportBakedTransform and ( nrTransformCurves >  0 ) ):
        
        animationInput = []
        animationOutput = []        
        
        sourceID = ipoName + '-Transform-Input'
        transformInputElement = dae.createSourceElement( sourceID, sourceID )
        floatArrayName = sourceID + "-Array"
        nrKeyFrames = ( transformXMax + 1 ) - transformXMin
        floatArrayTime = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName )
        floatArrayTime.setData( animationInput )
        floatArrayTime.setDataType( 'ANIMATIONINPUT-MATRIX' )
        transformInputElement.appendChild( floatArrayTime )

        # Create common profile technique
        technique = dae.createTechniqueElement( CP.COMMON )
        
        # Create accessor element with TIME param
        accessorTime = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 )
        paramTime = dae.createParamElement( None, CP.PN.TIME, "float", CP.FT.OUT )
        
        accessorTime.appendChild( paramTime )
        technique.appendChild( accessorTime )
        transformInputElement.appendChild( technique )
        # animationElement.appendChild( sourceElement )


        
        # Loop through Xmin to XMax
        for frame in range( transformXMin, transformXMax + 1 ):
            time = float( frame )
            animationInput.append( time )
            
            translateXYZ = Blender.Mathutils.Vector( )
            rotateXYZ = Blender.Mathutils.Vector( )
            sizeXYZ = Blender.Mathutils.Vector( )
            
            # Gather data
            for curve in transformCurves:
                curveName = curve.getName( )
                value = curve.evaluate( time )
                # print '%s: Time: %i Value: %f' % ( curveName, time, value )
                if ( curveName == 'LocX' ): translateXYZ.x = value
                elif ( curveName == 'LocY' ): translateXYZ.y = value
                elif ( curveName == 'LocZ' ): translateXYZ.z = value
                elif ( curveName == 'RotX' ): rotateXYZ.x = value * 10.0
                elif ( curveName == 'RotY' ): rotateXYZ.y = value * 10.0
                elif ( curveName == 'RotZ' ): rotateXYZ.z = value * 10.0
                elif ( curveName == 'SizeX' ): sizeXYZ.x = value
                elif ( curveName == 'SizeY' ): sizeXYZ.y = value
                elif ( curveName == 'SizeZ' ): sizeXYZ.z = value
            
            # Now add these values to our transformMatrix
            transformMatrix = Blender.Mathutils.ScaleMatrix( sizeXYZ.x, 4, Mathutils.Vector( 1.0, 0.0, 0.0  ) )
            transformMatrix *= Blender.Mathutils.ScaleMatrix( sizeXYZ.y, 4, Mathutils.Vector( 0.0, 1.0, 0.0  ) ) 
            transformMatrix *= Blender.Mathutils.ScaleMatrix( sizeXYZ.z, 4, Mathutils.Vector( 0.0, 0.0, 1.0  ) ) 
            transformMatrix *= Blender.Mathutils.RotationMatrix( rotateXYZ.x, 4, 'x' )
            transformMatrix *= Blender.Mathutils.RotationMatrix( rotateXYZ.y, 4, 'y' )
            transformMatrix *= Blender.Mathutils.RotationMatrix( rotateXYZ.z, 4, 'z' )
            transformMatrix *= Blender.Mathutils.TranslationMatrix( translateXYZ )
            
            # print transformMatrix
            animationOutput.append( transformMatrix )
        
        # Write animation output source...
        sourceID2 = ipoName + '-Transform-Output'
        transformOutputElement = dae.createSourceElement( sourceID2, sourceID2 )
        floatArrayName = sourceID2 + "-Array"
        floatArrayOutput = dae.createFloatArrayElement( nrKeyFrames * 16, floatArrayName, floatArrayName )
        floatArrayOutput.setData( animationOutput )
        floatArrayOutput.setDataType( 'ANIMATIONOUTPUT-MATRIX' )

        transformOutputElement.appendChild( floatArrayOutput )

        # Create common profile technique
        techniqueOutput = dae.createTechniqueElement( CP.COMMON )
        
        # Create accessor element with output param
        accessorOutput = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 16 )
        
        # Create float4x4 param element
        paramOutput = dae.createParamElement( None, CP.PN.MATRIX4X4, "float4x4", CP.FT.OUT )


        accessorOutput.appendChild( paramOutput )
        techniqueOutput.appendChild( accessorOutput )
        transformOutputElement.appendChild( techniqueOutput )
        # animationElement.appendChild( sourceElement )

        # Create sampler and channel elements for this baked transform

        
        sourceID = ipoName + '-Transform'
        samplerID = ipoName + '-Transform-Sampler'
        
        transformSamplerElement = dae.createSamplerElement( samplerID, samplerID )
        inputInput = dae.createInputElement( None, CP.IS.INPUT, sourceID + '-Input' )
        inputOutput = dae.createInputElement( None, CP.IS.OUTPUT, sourceID + '-Output' )
        transformSamplerElement.appendChild( inputInput )
        transformSamplerElement.appendChild( inputOutput )
        #animationElement.appendChild( samplerElement )
        
        
        # Create channel element
        channelID = ipoName + '-Transform-Channel'


        target = ipoOwner + '/transform'
        transformChannelElement = dae.createChannelElement( channelID, channelID, samplerID, target )

        # Add transform sources first
        animationElement.appendChild( transformInputElement )
        animationElement.appendChild( transformOutputElement )
        
    
##    # Else if transform is not baked:
##    else:
##        for curve in transformCurves:
##        
##            curveName = curve.getName( )
##            keyFrames = curve.getPoints( )
##            nrKeyFrames = len( keyFrames )
##            
##            # Create input source element
##            # TODO: If keyframe-input are same (same position-points) then perhaps create one input source?
##            sourceID = ipoName + "-" + curveName + "-Input"
##            sourceElement = dae.createSourceElement( sourceID, sourceID )
##            floatArrayName = sourceID + "-Array"
##            floatArrayTime = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName )
##            floatArrayTime.setData( keyFrames )
##            floatArrayTime.setDataType( 'ANIMATIONINPUT' )
##            sourceElement.appendChild( floatArrayTime )
##    
##            # Create common profile technique
##            technique = dae.createTechniqueElement( CP.COMMON )
##            
##            # Create accessor element with TIME param
##            accessorTime = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 )
##            paramTime = dae.createParamElement( None, CP.PN.TIME, "float", CP.FT.OUT )
##            
##            accessorTime.appendChild( paramTime )
##            technique.appendChild( accessorTime )
##            sourceElement.appendChild( technique )
##            animationElement.appendChild( sourceElement )
##
##
##            # Create output source element
##            sourceID2 = ipoName + "-" + curveName + "-Output"
##            sourceElement = dae.createSourceElement( sourceID2, sourceID2 )
##            floatArrayName = sourceID2 + "-Array"
##            floatArrayOutput = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName )
##            floatArrayOutput.setData( keyFrames )
##            if ( curveName == 'Hard' ):
##                floatArrayOutput.setDataType( 'ANIMATIONOUTPUT-SHININESS' )
##            else:
##                floatArrayOutput.setDataType( 'ANIMATIONOUTPUT' )
##    
##            sourceElement.appendChild( floatArrayOutput )
##    
##            # Create common profile technique
##            techniqueOutput = dae.createTechniqueElement( CP.COMMON )
##            
##            # Create accessor element with output param
##            accessorOutput = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 )
##            
##            # Create different params depending on curve name (this should be driven channel for objects but
##            # for now let's use the curve name because that seems to work)
##            paramOutput = getParamElementFromCurveName( curveName )
##    
##    
##            accessorOutput.appendChild( paramOutput )
##            techniqueOutput.appendChild( accessorOutput )
##            sourceElement.appendChild( techniqueOutput )
##            animationElement.appendChild( sourceElement )    
    
    
  
    # Now that we have written transform channels write every other channel
    # TODO: Combine channels if possible (for example RGB sources -> material diffuse channel)
    for curve in otherCurves:
        curveName = curve.getName( )
        keyFrames = curve.getPoints( )
        nrKeyFrames = len( keyFrames )
        
        # Create input source element
        # TODO: If keyframe-input are same (same position-points) then perhaps create one input source?
        sourceID = ipoName + "-" + curveName + "-Input"
        sourceElement = dae.createSourceElement( sourceID, sourceID )
        floatArrayName = sourceID + "-Array"
        floatArrayTime = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName )
        floatArrayTime.setData( keyFrames )
        floatArrayTime.setDataType( 'ANIMATIONINPUT' )
        sourceElement.appendChild( floatArrayTime )

        # Create common profile technique
        technique = dae.createTechniqueElement( CP.COMMON )
        
        # Create accessor element with TIME param
        accessorTime = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 )
        paramTime = dae.createParamElement( None, CP.PN.TIME, "float", CP.FT.OUT )
        
        accessorTime.appendChild( paramTime )
        technique.appendChild( accessorTime )
        sourceElement.appendChild( technique )
        animationElement.appendChild( sourceElement )


        # Create output source element
        sourceID2 = ipoName + "-" + curveName + "-Output"
        sourceElement = dae.createSourceElement( sourceID2, sourceID2 )
        floatArrayName = sourceID2 + "-Array"
        floatArrayOutput = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName )
        floatArrayOutput.setData( keyFrames )
        if ( curveName == 'Hard' ):
            floatArrayOutput.setDataType( 'ANIMATIONOUTPUT-SHININESS' )
        elif ( curveName == 'Alpha' ):
            floatArrayOutput.setDataType( 'ANIMATIONOUTPUT-ALPHA' )
        elif ( isRotationCurve( curveName ) ):
            floatArrayOutput.setDataType( 'ANIMATIONOUTPUT-ROTATION' )
        else:
            floatArrayOutput.setDataType( 'ANIMATIONOUTPUT' )
        sourceElement.appendChild( floatArrayOutput )

        # Create common profile technique
        techniqueOutput = dae.createTechniqueElement( CP.COMMON )
        
        # Create accessor element with output param
        accessorOutput = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 )
        
        # Create different params depending on curve name (this should be driven channel for objects but
        # for now let's use the curve name because that seems to work)
        paramOutput = getParamElementFromCurveName( curveName )


        accessorOutput.appendChild( paramOutput )
        techniqueOutput.appendChild( accessorOutput )
        sourceElement.appendChild( techniqueOutput )
        animationElement.appendChild( sourceElement ) 
    
    
    
    # Add transform sampler element first
    if ( transformSamplerElement != None ):
        animationElement.appendChild( transformSamplerElement )

    # Add other samples
    for curve in otherCurves:
        
        curveName = curve.getName( )        
        sourceID = ipoName + "-" + curveName
        
        # Create sampler element
        samplerID = ipoName + "-" + curveName + '-Sampler'
        samplerElement = dae.createSamplerElement( samplerID, samplerID )
        
        # Create input semantics
        inputInput = dae.createInputElement( None, CP.IS.INPUT, sourceID + '-Input' )
        inputOutput = dae.createInputElement( None, CP.IS.OUTPUT, sourceID + '-Output' )        

        samplerElement.appendChild( inputInput )
        samplerElement.appendChild( inputOutput )
        animationElement.appendChild( samplerElement )
    
    
    # Add transform channel element first
    if ( transformChannelElement != None ):    
        animationElement.appendChild( transformChannelElement )
    
    # TODO: Write other channels here
    for curve in otherCurves:
        
        curveName = curve.getName( )
        sourceID = ipoName + "-" + curveName + '-Sampler'
        
        # Create channel element
        channelID = ipoName + "-" + curveName + '-Channel'
        
        # Get IPO Curve driver object
        # Important! If this is a animation channel that is not targetet against
        # a transform then target lib instead (add '-Lib' to target id)
        if ( not isTransformCurve( curveName ) ):
            target = ipoOwner + '-Lib/' + getTargetNameFromCurveName( curveName )
        else:
            target = ipoOwner + '/' + getTargetNameFromCurveName( curveName )
        
        
        channelElement = dae.createChannelElement( channelID, channelID, sourceID, target )
        animationElement.appendChild( channelElement )
    
    libraryElement.appendChild( animationElement )

# Write transform animation first
##    if ( exportBakedTransform ):
##        
##        transformXMin = 1000.0
##        transformXMax = -1000.0
##
##        # Store which IPO curves that are transform based
##        transformCurves = []
##
##        # Create sources for each curve
##        for curve in curves:
##
##        # Get information about our Ipo curve
##        curveName = curve.getName( ) 
##        
##        # Get control points (keyframes)
##        keyFrames = curve.getPoints( )
##        nrKeyFrames = len( keyFrames )
##
##        # Get the min and max values from this curve
##        if ( exportBakedTransform ):
##            if ( isTransformCurve( curveName ) ):
##                for keyFrame in keyFrames:
##                    points = keyFrame.getPoints( )            
##                    if ( points[ 0 ] < transformXMin ):
##                        transformXMin = points[ 0 ]
##                    if ( points[ 0 ] > transformXMax ):
##                        transformXMax = points[ 0 ]
##            print curveName + ' has Xmin[%f] and Xmax[%f]' % ( transformXMin, transformXMax )
##        else:
##            # Create input source element
##            # TODO: If keyframe-input are same (same position-points) then perhaps create one input source?
##            sourceID = ipoName + "-" + curveName + "-Input"
##            sourceElement = dae.createSourceElement( sourceID, sourceID )
##            floatArrayName = sourceID + "-Array"
##            floatArrayTime = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName )
##            floatArrayTime.setData( keyFrames )
##            floatArrayTime.setDataType( 'ANIMATIONINPUT' )
##            sourceElement.appendChild( floatArrayTime )
##    
##            # Create common profile technique
##            technique = dae.createTechniqueElement( CP.COMMON )
##            
##            # Create accessor element with TIME param
##            accessorTime = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 )
##            paramTime = dae.createParamElement( None, CP.PN.TIME, "float", CP.FT.OUT )
##            
##            accessorTime.appendChild( paramTime )
##            technique.appendChild( accessorTime )
##            sourceElement.appendChild( technique )
##            animationElement.appendChild( sourceElement )
##
##
##            # Create output source element
##            sourceID2 = ipoName + "-" + curveName + "-Output"
##            sourceElement = dae.createSourceElement( sourceID2, sourceID2 )
##            floatArrayName = sourceID2 + "-Array"
##            floatArrayOutput = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName )
##            floatArrayOutput.setData( keyFrames )
##            floatArrayOutput.setDataType( 'ANIMATIONOUTPUT' )
##    
##            sourceElement.appendChild( floatArrayOutput )
##    
##            # Create common profile technique
##            techniqueOutput = dae.createTechniqueElement( CP.COMMON )
##            
##            # Create accessor element with output param
##            accessorOutput = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 )
##            
##            # Create different params depending on curve name (this should be driven channel for objects but
##            # for now let's use the curve name because that seems to work)
##            paramOutput = getParamElementFromCurveName( curveName )
##    
##    
##            accessorOutput.appendChild( paramOutput )
##            techniqueOutput.appendChild( accessorOutput )
##            sourceElement.appendChild( techniqueOutput )
##            animationElement.appendChild( sourceElement )
##
##    
##    # If baking animation:
##    # Loop through 
##    # if ( exportBakedTransform ):    
##    
##    
##    
##    
##    # Create sampler element
##    for curve in curves:    
##        
##        curveName = curve.getName( )        
##        
##        sourceID = ipoName + "-" + curveName
##        
##        # Create sampler element
##        samplerID = ipoName + "-" + curveName + '-Sampler'
##        samplerElement = dae.createSamplerElement( samplerID, samplerID )
##        
##        # Create input semantics
##        inputInput = dae.createInputElement( None, CP.IS.INPUT, sourceID + '-Input' )
##        inputOutput = dae.createInputElement( None, CP.IS.OUTPUT, sourceID + '-Output' )
##        
##        samplerElement.appendChild( inputInput )
##        samplerElement.appendChild( inputOutput )
##        animationElement.appendChild( samplerElement )
##    
##    
##    # Create channel element
##    for curve in curves:    
##        
##        curveName = curve.getName( )        
##        
##        sourceID = ipoName + "-" + curveName + '-Sampler'
##        
##        # Create channel element
##        channelID = ipoName + "-" + curveName + '-Channel'
##        
##        # Get IPO Curve driver object
##        target = ipoOwner + '/' + getTargetNameFromCurveName( curveName )
##        channelElement = dae.createChannelElement( channelID, channelID, sourceID, target )
##        
##        animationElement.appendChild( channelElement )
##        
##    
##    libraryElement.appendChild( animationElement )


# Write camera information to dae file
def writeCamera( libraryElement, camera ):
    
    cameraName = camera.getName()
    cameraID = cameraName + "-Lib" 
    cameraType = camera.getType()
    cameraElement = dae.createCameraElement( cameraID, cameraName )
    technique = dae.createTechniqueElement( CP.COMMON )
    optics = dae.createOpticsElement( )
    
    # Create PERSPECTIVE camera or ORTHO camera
    program = None
    
    # PERSPECTIVE Camera
    # print cameraType
    if ( cameraType == 0 ):
        program = dae.createProgramElement( None, None, CP.PIAU.str[ CP.PIAU.PERSPECTIVE ] )
        paramYFOV = dae.createParamElement( None, CP.PN.YFOV, "float", CP.FT.IN, None, None )
        #paramXFOV = dae.createParamElement( None, CP.PN.XFOV, "float", CP.FT.IN, None, None )
        
        # Calculate Y-FOV based on LENS value
        lens = camera.getLens( )
        yfov = 2 * ( math.atan( 16.0 / lens ) ) * ( 180.0 / 3.1415926 )
        
        paramYFOV.setData( "%.6f" % yfov )
        program.appendChild( paramYFOV )
        
        #paramXFOV.setData( "%.6f" % xfov )
        #program.appendChild( paramXFOV )
        
    else:
        print "Warning! Orthographic cameras not supported. Camera not exported! "
        return
        #program = dae.createProgramElement( None, CP.PIAU.str[ CP.PIAU.ORTHOGRAPHIC ], None )
    
    paramZNear = dae.createParamElement( None, CP.PN.ZNEAR, "float", CP.FT.IN, None, None )
    paramZFar = dae.createParamElement( None, CP.PN.ZFAR, "float", CP.FT.IN, None, None )
    znear = camera.getClipStart( )
    zfar = camera.getClipEnd( )
    paramZNear.setData( "%.6f" % znear )
    paramZFar.setData( "%.6f" % zfar )
    program.appendChild( paramZNear )
    program.appendChild( paramZFar )
    optics.appendChild( program )
    technique.appendChild( optics )
    cameraElement.appendChild( technique )
    libraryElement.appendChild( cameraElement )




# --- Write header information to dae file ---
def writeHeader( colladaElement ):
    
    # Write asset information
    asset = dae.createAssetElement( )
    
    author = dae.createAuthorElement( __author__ )
    authoringtooldata = "Blender " + "%i" % Blender.Get( 'version' ) + " COLLADA Exporter"
    authoringtool = dae.createAuthoringToolElement( authoringtooldata )
    
    # Can I change this in Blender?
    upaxisdata = "Z_UP"
    upaxis = dae.createUpAxisElement( upaxisdata )
    
    # createddata = date( 2005, 12, 21)
    # created = dae.createCreatedElement( createddata )

    # Create a unit element (mostly for Maya import to work better )
    unit = dae.createUnitElement( 'centimeter', '%s' % 0.01 )
    
    
    asset.appendChild( author )
    asset.appendChild( authoringtool )
    asset.appendChild( upaxis )
    asset.appendChild( unit )
    colladaElement.appendChild( asset )

# --- Write libraries to dae file ---
def writeLibrary( colladaElement ):

    
    imageLibraryElement = dae.createLibraryElement( CP.LT.IMAGE )
    textureLibraryElement = dae.createLibraryElement( CP.LT.TEXTURE )
    materialLibraryElement = dae.createLibraryElement( CP.LT.MATERIAL )
    geometryLibraryElement = dae.createLibraryElement( CP.LT.GEOMETRY )
    animationLibraryElement = dae.createLibraryElement( CP.LT.ANIMATION )   
    lightLibraryElement = dae.createLibraryElement( CP.LT.LIGHT )
    cameraLibraryElement = dae.createLibraryElement( CP.LT.CAMERA )
    
    meshes = dict()
    lights = dict()
    cameras = dict()
    ipos = dict()

    for obj in objects:
        objType = obj.getType( )
        dataName = obj.getData( True )
        data = obj.getData( False )
        ipo = obj.getIpo( )
        objName = obj.name
        if ( ipo != None ):
            ipos[ objName ] = ipo
        if ( objType == 'Mesh' ):
            meshes[ dataName ] = NMesh.GetRaw( dataName )
        elif ( objType == 'Lamp' ):
            lights[ dataName ] = data
        elif ( objType == 'Camera' ):
            cameras[ dataName ] = data
    


    # Get raw meshes
    materials = dict()
    nrMeshes = len( meshes )
    if ( nrMeshes > 0 ):
        progress = 0.0
        addProgress = 1.0 / nrMeshes
        Window.DrawProgressBar( 0.0, "Writing mesh data..." )
        for key in meshes:
            rawMesh = meshes[ key ]
            if ( rawMesh.users > 0 ):
                writeMesh( geometryLibraryElement, rawMesh )
                progress += addProgress
                Window.DrawProgressBar( progress, "Exporting geometry %.0f %%..." % ( progress * 100.0 ) )
                meshMaterials = rawMesh.getMaterials( -1 )
                for material in meshMaterials:
                    key = material.getName( )
                    materials[ key ] = material
                    
                    # Ipo on material?
                    ipo = material.getIpo( )
                    if ( ipo != None ):
                        ipos[ key ] = ipo
    
    
    # Get materials
    textures = dict()
    nrMaterials = len( materials )
    if ( nrMaterials > 0 ):
        progress = 0.0
        addProgress = 1.0 / nrMaterials
        for key in materials:
            material = materials[ key ]
            writeMaterial( materialLibraryElement, material )
            progress += addProgress
            Window.DrawProgressBar( progress, "Exporting materials %.0f %%..." % ( progress * 100.0 ) )
            materialTextures = material.getTextures( )
            for texture in materialTextures:
                if not ( texture == None ):
                    if ( texture.tex.type == Texture.Types.IMAGE ):
                        key = texture.tex.getName( )
                        textures[ key ] = texture.tex
        
                        # Ipo on texture?
                        ipo = texture.tex.getIpo( )
                        if ( ipo != None ):
                            ipos[ key ] = ipo    

    
    # Write textures
    images = dict()
    nrTextures = len( textures )
    if ( nrTextures > 0 ):
        progress = 0.0
        addProgress = 1.0 / nrTextures
        for key in textures:
            texture = textures[ key ]
            writeTexture( textureLibraryElement, texture )
            progress += addProgress
            Window.DrawProgressBar( progress, "Exporting textures %.0f %%..." % ( progress * 100.0 ) )
            image = texture.getImage( )
            if ( image != None ):
                imageName = image.getName( )
                images[ imageName ] = image

   
 
    # Write images
    nrImages = len( images )
    if ( nrImages > 0 ):
        progress = 0.0
        addProgress = 1.0 / nrImages
        for key in images:
            image = images[ key ]
            writeImage( imageLibraryElement, image )
            progress += addProgress
            Window.DrawProgressBar( progress, "Exporting images %.0f %%..." % ( progress * 100.0 ) )
    
    
    # Write lights
    nrLights = len( lights )
    if ( nrLights > 0 ):
        progress = 0.0
        addProgress = 1.0 / nrLights
        for key in lights:
            light = lights[ key ]
            writeLight( lightLibraryElement, light )
            progress += addProgress
            Window.DrawProgressBar( progress, "Exporting lights %.0f %%..." % ( progress * 100.0 ) )
    
    # Write cameras
    nrCameras = len( cameras )
    if ( nrCameras > 0 ):
        progress = 0.0
        addProgress = 1.0 / nrCameras
        for key in cameras:
            camera = cameras[ key ]
            writeCamera( cameraLibraryElement, camera )
            progress += addProgress
            Window.DrawProgressBar( progress, "Exporting cameras %.0f %%..." % ( progress * 100.0 ) )
    
    
    # Write animations
    nrAnimations = len( ipos )
    if ( nrAnimations > 0 ):
        progress = 0.0
        addProgress = 1.0 / nrAnimations
        for key in ipos:
            ipo = ipos[ key ]
            writeAnimation( animationLibraryElement, ipo, key )
            progress += addProgress
            Window.DrawProgressBar( progress, "Exporting animation %.0f %%..." % ( progress * 100.0 ) )

    # Write library element. Put animation first...


    colladaElement.appendChild( imageLibraryElement )
    colladaElement.appendChild( textureLibraryElement )
    colladaElement.appendChild( materialLibraryElement )
    colladaElement.appendChild( geometryLibraryElement )
    colladaElement.appendChild( lightLibraryElement )
    colladaElement.appendChild( cameraLibraryElement )
    colladaElement.appendChild( animationLibraryElement )

# --- Write node to dae ---
def writeNode( object, parentNode ):

    global exportBakedTransform
    
    newNodeName = object.name
    # newNodeName = object.name + "-Node"
    newNode = dae.createNodeElement( newNodeName, newNodeName, CP.NT.NODE )

    #print "Creating %s" % newNodeName
        
    # Create data for this node here
    url = object.getData( True )
    if not ( url == None ):
        url += "-Lib"
        instance = dae.createInstanceElement( url )
        newNode.appendChild( instance )
    
    
    # No need to check for IPO connection here simply output sid values anyway. 
    # sid values are according to target values in library and these
    # names follows the naming convention that the Maya exporter use
    
    #sidTranslate = newNodeName + "-Translate"
    #sidRotateX = newNodeName + "-Rotate-X" 
    if ( exportBakedTransform ):
        matrixElement = dae.createMatrixElement( 'transform' )
        matrix = object.getMatrix( 'localspace' )
        data = ""
        matrix.transpose()
        if ( niceFormat ):
            for i in range( 4 ):
                data += "\n%.6f %.6f %.6f %.6f" % ( matrix[ i ].x, matrix[ i ].y,
                                                    matrix[ i ].z, matrix[ i ].w )
        else:
            data += "%.6f %.6f %.6f %.6f " % ( matrix[ 0 ].x, matrix[ 0 ].y,
                                               matrix[ 0 ].z, matrix[ 0 ].w )
            data += "%.6f %.6f %.6f %.6f " % ( matrix[ 1 ].x, matrix[ 1 ].y,
                                               matrix[ 1 ].z, matrix[ 1 ].w )
            data += "%.6f %.6f %.6f %.6f " % ( matrix[ 2 ].x, matrix[ 2 ].y,
                                               matrix[ 2 ].z, matrix[ 2 ].w )                
            data += "%.6f %.6f %.6f %.6f" % ( matrix[ 3 ].x, matrix[ 3 ].y,
                                              matrix[ 3 ].z, matrix[ 3 ].w )                


        matrixElement.setData( data )
        newNode.appendChild( matrixElement )
    else:
        translate = dae.createTranslateElement( 'translate' )
        rotateX = dae.createRotateElement( 'rotateX' )
        rotateY = dae.createRotateElement( 'rotateY' )
        rotateZ = dae.createRotateElement( 'rotateZ' )
        scale = dae.createScaleElement( 'scale' )
        location = object.getLocation()
        rotation = object.getEuler()
        size = object.getSize()
        data = "%.6f %.6f %.6f" % ( location[ 0 ], location[ 1 ], location[ 2 ] )
        dataX = "1 0 0 %.6f" % ( toAngle( rotation[ 0 ] ) )
        dataY = "0 1 0 %.6f" % ( toAngle( rotation[ 1 ] ) )
        dataZ = "0 0 1 %.6f" % ( toAngle( rotation[ 2 ] ) )
        dataScale = "%.6f %.6f %.6f" % ( size[ 0 ], size[ 1 ], size[ 2 ] )
        translate.setData( data )
        rotateX.setData( dataX )
        rotateY.setData( dataY )
        rotateZ.setData( dataZ )
        scale.setData( dataScale )
        newNode.appendChild( translate )
        newNode.appendChild( rotateX )
        newNode.appendChild( rotateY )    
        newNode.appendChild( rotateZ )
        newNode.appendChild( scale )
    
    # Check if anyone has Me as Parent
    returnNode = None
    for child in objects:
        parent = child.getParent()
        if ( object == parent ):
            returnNode = writeNode( child, newNode )
            if not ( returnNode == None ):
                newNode.appendChild( returnNode )

    parentNode.appendChild( newNode )
    
    return newNode

# --- Write scene to dae file ---
def writeScene( colladaElement ):

    # Write <scene> element
    currentScene = Scene.GetCurrent( )
    sceneName = currentScene.getName( )
    sceneElement = dae.createSceneElement( sceneName, sceneName )
    colladaElement.appendChild( sceneElement )
    
    
    # Write nodes
    if not ( objects == None ):
        nrObjects = len( objects )
        if ( nrObjects > 0 ):
            addProgress = 1.0 / nrObjects
            progress = 0.0
            Window.DrawProgressBar( 0.0, "Exporting Scene 0.0% ..." )
            for object in objects:
                if ( object.getParent() == None ):
                    writeNode( object, sceneElement )
                    progress += addProgress
                    Window.DrawProgressBar( progress, "Exporting Scene %.0f%% ..." % ( progress * 100.0 ) )
            Window.DrawProgressBar( 1.0, "Finished!" )

    # print objects

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









# ----------------------------------------------
#    HELPER FUNCTIONS
# ----------------------------------------------

# --- Set id and name tag to element ---
#def setIdAndName( element, string ):
    
#    element.setAttribute( "id", string )
#    element.setAttribute( "name", string )
    
#    return

# --- Create COMMON Technique element ---
#def createCommonTechnique( ):
#    technique = dae.createElement( "technique" )    
#    technique.setAttribute( "profile", "COMMON" )
#
#    return technique

# --- Create Param element ---
#def createParamElement( name, type ):
#    param = dae.createElement( "param" )    
#    param.setAttribute( "name", name )
#    param.setAttribute( "type", type )
#
#    return param



# ----------------------------------------------
# --- MAIN ---
def main( filePath ):
    global dae
    global objects
    global exportSelected
    global fps

    if not ( filePath == None ):
        
        print "Exporting: " + filePath + "..."

        startTime = sys.time()
            
        dae = COLLADADocument()
        dae.openFile( filePath )
        
        # Build node tree here
        collada = dae.createCOLLADAElement( )
        dae.appendChild( collada )
    
        if ( exportSelected == True ):
            objects = Object.GetSelected( )
            # print "Selected objects only!"
        else:
            objects = Object.Get( )    
    
        # Write header information
        writeHeader( collada )
        
        # Set fps
        scn = Scene.GetCurrent( )
        context = scn.getRenderingContext( )
        fps = context.framesPerSec( )

        #Write library information
        writeLibrary( collada )
        
        # Write scene information
        writeScene( collada )
        
        dae.buildXML( )
        dae.cleanUp( )
        
        
        # Get scene objects
        # objects = Object.Get()
    
        endTime = sys.time()
        
        exportTime = endTime - startTime
        print "Export time: %.6f" % (exportTime )
        #print "</COLLADA Exporter v0.1>"

    # Window.DrawProgressBar( 1.0, "" )


def callback_fileselector( filename ):
    if ( sys.exists( filename ) == 1 ):
        overwrite = Draw.PupMenu( "File Already Exists, Overwrite?%t|Yes%x1|No%x0" )
        if ( overwrite == 1 ):
            main( filename )
    else:
        main( filename )


def ExportGUI( ):
    global exportSelected, exportBakedTransform
    
    # Window.DrawProgressBar( 0.0, ">>> COLLADA-" )    
    
    # print "<COLLADA Exporter v0.1>"
    
    # Export selected or all
    progressString = "COLLADA-"
    answer = Draw.PupMenu( "Export what?%t|All%x1|Selected only%x0" )
    if ( answer == 1 ):
        exportSelected = False
        progressString += "All-"
    elif ( answer == 0 ):
        exportSelected = True
        progressString +="Selected-"
    else:
        # print "</COLLADA Exporter v0.1>"
        # Window.DrawProgressBar( 1.0, "" )
        return
    
    # Window.DrawProgressBar( 0.0, progressString )
    answer2 = Draw.PupMenu( "Export as matrix element?%t|Yes%x1|No%x0" )
    if ( answer2 == 1 ):
        exportBakedTransform = True
        progressString +="Matrix"
    elif ( answer2 == 0 ):
        exportBakedTransform = False
        progressString +="Transform"
    else:
        # print "</COLLADA Exporter v0.1>"
        # Window.DrawProgressBar( 1.0, "" )
        return

    # Window.DrawProgressBar( 0.0, progressString )
    
    print "Export options: " + progressString
    
    defaultFileName = Blender.Get('filename') + ".dae"
    defaultFileName = defaultFileName.replace( '.blend', '' )
    Window.FileSelector( callback_fileselector, 'Export .dae', defaultFileName )
    



# Run the script
if not ( _ERROR == True ):
    ExportGUI()
    
#main( 'C:\\ColladaBlender\\test.xml' )
