var SwiffClass = new Native({

	name: 'SwiffClass',

	initialize: function(file, params, props){
	
		function createSwiff(self, p){
			var ps = $extend(props || {}, p || {});
			var id = ps.id;
			delete ps.id;
			if(!self.$swiff)
				self.$swiff = new Swiff(file, { id: id, properties: ps, params: params || {}, callBacks: {onSwiffClassLoad: function(){
					if(self.$swiff) initSwiff.apply(self, arguments);
					else initSwiff.delay(100, self, arguments);
				}}});
			else if(props)
				self.$swiff.toElement().setProperties(props);
		}
		
		function initSwiff(methods){
			var self = this,
			swiff = this.$swiff,
			internalFunctions = {},
			externalFunctions = {},
			internalFunctionID = 0;

			SwiffClass.Fn[swiff.instance] = {};
			
			methods.each(function(method){
				if(method != 'initialize'){
					self[method] = function(){ return convertFromExternal(swiff.remote(method, convertToExternal($A(arguments)))); };
				}
			});
			if(methods.contains('initialize')){
				swiff.remote('initialize', convertToExternal(self.$initargs));
				delete self.$initargs;
			}
			
			function convertFromExternal(obj){
				switch($type(obj)){
					case 'object':
						for(var s in obj)
							obj[s] = convertFromExternal(obj[s]);
						break;
					case 'array':
						for(var i = 0; i < obj.length; i++)
							obj[i] = convertFromExternal(obj[i]);
						break;
					case 'string':
						if(obj.substr(0, 14) == 'SwiffClass.Fn.')
							return getFunctionFromExternalID(obj);
				}
				return obj;
			}
			
			function getFunctionFromExternalID(id){
				if(externalFunctions[id]) return externalFunctions[id];
				return externalFunctions[id] = function(){ return convertFromExternal(swiff.remote(id, convertToExternal($A(arguments)))); };
			}
			
			function convertToExternal(obj){
				switch($type(obj)){
					case 'object':
						for(var s in obj)
							obj[s] = convertToExternal(obj[s]);
						break;
					case 'array':
						for(var i = 0; i < obj.length; i++)
							obj[i] = convertToExternal(obj[i]);
						break;
					case 'function':
						return getInternalIDFromFunction(obj);
				}
				return obj;
			}
			
			function getInternalIDFromFunction(fn){
				for(var id in internalFunctions) if(internalFunctions[id] === fn) return id;
				var id = (++internalFunctionID);
				SwiffClass.Fn[swiff.instance]['Fn' + id] = function(args){ return convertToExternal(fn.apply(self, convertFromExternal(args))); };
				id = 'SwiffClass.Fn.' + swiff.instance + '.Fn' + id;
				internalFunctions[id] = fn;
				return id;
			}
		}
		
		var klass = function(empty){
			this.constructor = klass;
			if (empty === $empty) return this;
			this.$initargs = $A(arguments);
			return this;
		};

		$extend(klass, this);
		klass.constructor = SwiffClass;
		klass.prototype = {
		
			toElement: function(){
				createSwiff(this);
				return this.$swiff.toElement();
			},
			
			replaces: function(element, props){
				createSwiff(this, props);
				this.$swiff.replaces(element);
				return this;
			},
			
			inject: function(element, props){
				createSwiff(this, props);
				this.$swiff.inject(element);
				return this;
			}
		};
		return klass;
	}
});

SwiffClass.Fn = {};

SwiffClass.implement({
	implement: function(){
		Class.Mutators.Implements(this.prototype, Array.slice(arguments));
		return this;
	}
});
