define([
	"backbone"
	, "models/dmap-type"
	, "collections/dmap"
]
, function (Backbone, DMAPType, DMAPCollection) {	
	var that

	, Model	= Backbone.Model.extend({
		idAttribute:	"_id"

		, initialize:	function (attributes, options) {
			that	= this;

			this.contentCodes = options && options.contentCodes || null;
			console.log("Initial", options, this.contentCodes);

			if (options.buffer instanceof ArrayBuffer) {
				attributes	= parseWrapper(options.buffer);
				delete options.buffer;

				this.set(attributes);
			}

			return this;
		}
/*
		, set:			function (attributes, options) {
			console.log(attributes, options);

			this._id	= attributes["dmap.persistentid"] || attributes["dmap.itemid"] || attributes["dmap.containeritemid"];
			
			Model.__super__.set(this, arguments);
			
			return this;
		}
*/
		, update:		function (attributes, options) {
			that.trigger("dmap.model.update", this, arguments);

			return that.apply(that, arguments);
		}

		, parse:		function (reponse) {
			return that.attributes;
		}

		, fetch:		function (options) {
			that.trigger("dmap.model.fetch", this, arguments);

			return that;
		}

		, save:			function (attributes, options) {
			that.trigger("dmap.model.save", this, arguments);

			return that;
		}

		, destroy:		function (options) {
			that.trigger("dmap.model.destroy", this, arguments);

			return that;
		}

		, unset:		function (options) {
			that.trigger("dmap.model.unset", this, arguments);

			return that;
		}

		, clear:		function (options) {
			that.trigger("dmap.model.unset", this, arguments);

			return that;
		}
	})

	, parseCodeDictionnary	= function(dictChunk) {
		var codeElement	= {};
		
		while (dictChunk.byteLength > 8) {
			var contentCode		= DMAPType.getType(dictChunk);
			var contentLength	= DMAPType.getInt32(dictChunk.slice(4,8));
			//console.log(contentLength);

			switch (contentCode) {
				case 'mcnm':
					codeElement.code	= DMAPType.getString(dictChunk.slice(8, 8+contentLength));
				break;
				
				case 'mcna':
					var codeName		= DMAPType.getString(dictChunk.slice(8, 8+contentLength));
					codeElement.name	= codeName.replace(/\./g, '_');
					//console.log(codeElement.name);
				break;
				
				case 'mcty':
					var typeData		= DMAPType.getInt16(dictChunk.slice(8, 8+contentLength));
					codeElement.type	= new DMAPType(typeData);
				break;
			}
			
			dictChunk	=	dictChunk.slice(8+contentLength);
		}
		
		return codeElement;
	}

	, parseBinaryChunk		= function (binaryChunk) {
		var entry	= {};
		
		while (binaryChunk.byteLength > 8) {
			var tagName		= DMAPType.getType(binaryChunk);
			var tagLength	= DMAPType.getInt32(binaryChunk.slice(4,8));
			//console.debug(codeInfo, tagName, tagLength);

			if (that.contentCodes	=== null) {
				switch (tagName) {
					case 'mdcl':
						var contentCode		= parseCodeDictionnary(binaryChunk.slice(8, 8+tagLength));
						var codeId			= contentCode.code.toLowerCase();

						entry[codeId]		= _.extend({}, contentCode, contentCode.type);
					break;
					
					case 'mstt':
						// Nothing to do with the status, skip it
					break;
				}
			} else {
				var codeInfo	= that.contentCodes.get(tagName);

				if (codeInfo) {
					if (codeInfo.type === 12) {
						if (typeof entry[codeInfo.name] === "undefined") {
							// Here we might want to select different collection types depending on the tag
							entry[codeInfo.name]	= new DMAPCollection();
						}

						entry[codeInfo.name].add(binaryChunk.slice(8, tagLength), {silent: true});
					} else {
						//console.log(codeInfo);
						entry[codeInfo.name]		= codeInfo.unpack(binaryChunk.slice(8), tagLength);
					}
				} else {
					// TODO: we should try to guess.
					console.info("Unknown type: " + tagName + "(" + tagLength + ")");
				}
			}

			binaryChunk	= binaryChunk.slice(8 + tagLength);
		}

		return entry;
	}

	, parseWrapper		= function(binaryData) {
		console.log(DMAPType);
		var containerType	= DMAPType.getType(binaryData);
		//var binaryLength	= DMAPType.getUint32(binaryData.slice(4,8));
		var contentData		= binaryData.slice(8);
		
		switch (containerType) {
			// Update
			case "mupd":
				// Unsupported
				return;
			break;

			default:
				console.info("Unknown type: " + containerType/*, binaryLength*/, contentData);
			// Content codes
			case "mccr":
			// Server Info
			case "msrv":
			// Login
			case "mlog":
			// Database
			case "adbs":
			// Database info
			case "avdb":
			// Playlist info
			case "aply":
			// List of songs
			case "apso":
				return parseBinaryChunk(contentData);
			break;
		}
	}
;

	return Model;
});