/**
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */
/**
 * @fileoverview contains the TsRef class
 * and the TsRefProperty and TsRefType helper classes
 */

/**
 * @class Represents a TsRefProperty in the tree
 *
 * @constructor
 */
var TsRefProperty = function(parentType,name,value) {
	this.parentType = parentType;
	this.name = name;
	this.value = value;
	var descriptionCache = null;
	this.getDescription = function(callBack) {
		if(descriptionCache == null){
			var urlParameters = '&typeId=' + this.parentType + '&parameterName=' + this.name;

			new Ajax.Request(
				T3editor.URL_typo3 + TYPO3.settings.ajaxUrls['T3Editor_TSrefLoader::getDescription'],
				{
					method: 'get',
					parameters: urlParameters,
					onSuccess: function(transport) {
						descriptionCache = transport.responseText;
						callBack(transport.responseText);
					}
				}
			);
		} else {
			callBack(descriptionCache);
		}
	}
}

/**
 * @class Represents a TsRefType in the tree
 *
 * @constructor
 */
var TsRefType = function(typeId) {
	this.typeId = typeId;
	this.properties = new Array();

	// todo: types can have descriptions too!
	this.getDescription = function() {
	}
}

/**
 * Construct a new TsRef object.
 * @class This class receives the TsRef from the server and represents it as a tree
 * also supplies methods for access to treeNodes
 *
 * @constructor
 * @return A new TsRef instance
 */
var TsRef = function() {
	var typeTree = new Array();

	var doc;

	this.loadTsrefAsync = function() {
		new Ajax.Request(
			T3editor.URL_typo3 + TYPO3.settings.ajaxUrls['T3Editor_TSrefLoader::getTypes'],
			{
				method: 'get',
				onSuccess: function(transport) {
					doc = eval('('+ transport.responseText +')');
					buildTree();
				}
			}
		);
	}

	function buildTree() {

		typeTree = new Array();
		for (var typeId in doc) {

			var arr = doc[typeId];
			typeTree[typeId] = new TsRefType(typeId);

			if (arr['extends'] != null) {
				typeTree[typeId]['extends'] = arr['extends'];
			}
			for (propName in arr.properties) {
				var propType = arr.properties[propName].type;
				typeTree[typeId].properties[propName] = new TsRefProperty(typeId,propName,propType);
			}
		}
		for (var typeId in typeTree) {
			if (typeTree[typeId]['extends'] != null) {
				//console.log(typeId+" | "+typeTree[typeId].extends+" |");
				addPropertiesToType(typeTree[typeId], typeTree[typeId]['extends'], 100);
			}
		}
	}

	function addPropertiesToType(addToType,addFromTypeNames,maxRecDepth){
		if(maxRecDepth<0){
			throw "Maximum recursion depth exceeded while trying to resolve the extends in the TSREF!";
			return;
		}
		var exts = addFromTypeNames.split(',');
		var i;
		for(i=0;i<exts.length;i++){
			//"Type 'array' which is used to extend 'undefined', was not found in the TSREF!"
			if(typeTree[exts[i]]==null){
				//console.log("Error: Type '"+exts[i]+"' which is used to extend '"+addToType.typeId+"', was not found in the TSREF!");
			}else{
				if(typeTree[exts[i]]['extends'] != null){
					addPropertiesToType(typeTree[exts[i]],typeTree[exts[i]]['extends'],maxRecDepth-1);
				}
				var properties = typeTree[exts[i]].properties;
				for(propName in properties){
					// only add this property if it was not already added by a supertype (subtypes override supertypes)
					if(addToType.properties[propName] == null){
						addToType.properties[propName] = properties[propName];
					}
				}
			}
		}
	}

	this.getPropertiesFromTypeId = function(tId) {
		if (typeTree[tId] != null) {
			// clone is needed to assure that nothing of the tsref is overwritten by user setup
			typeTree[tId].properties.clone = function() {
				var result = new Array();
				for (key in this) {
					result[key] = new TsRefProperty(this[key].parentType,this[key].name,this[key].value);
				}
				return result;
			}
			return typeTree[tId].properties;
		} else {
			return new Array();
		}
	}

	this.typeHasProperty = function(typeId,propertyName) {
		if (typeTree[typeId] != null && typeTree[typeId].properties[propertyName] != null) {
			return true;
		} else {
			return false;
		}
	}

	this.getType = function(typeId){
		return typeTree[typeId];
	}
	this.isType = function(typeId){
		return (typeTree[typeId] != null);
	}
}