//euler sources from quternion sources
float *AnimationExporter::get_eul_source_for_quat(Object *ob)
{
	FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
	const int keys = fcu->totvert;  
	float *quat = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 4, "quat output source values");
	float *eul = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 3, "quat output source values");
	float temp_quat[4];
	float temp_eul[3];
	while (fcu) {
		char *transformName = extract_transform_name(fcu->rna_path);

		if (!strcmp(transformName, "rotation_quaternion") ) {
			for (int i = 0; i < fcu->totvert; i++) {
				*(quat + (i * 4) + fcu->array_index) = fcu->bezt[i].vec[1][1];
			}
		}
		fcu = fcu->next;
	}

	for (int i = 0; i < keys; i++) {
		for (int j = 0; j < 4; j++)
			temp_quat[j] = quat[(i * 4) + j];

		quat_to_eul(temp_eul, temp_quat);

		for (int k = 0; k < 3; k++)
			eul[i * 3 + k] = temp_eul[k];

	}
	MEM_freeN(quat);
	return eul;

}
std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
{
	std::string tm_name;
	// when given rna_path, determine tm_type from it
	if (rna_path) {
		char *name = extract_transform_name(rna_path);

		if (!strcmp(name, "lens"))
			tm_type = 0;
		else if (!strcmp(name, "ortho_scale"))
			tm_type = 1;
		else if (!strcmp(name, "clip_end"))
			tm_type = 2;
		else if (!strcmp(name, "clip_start"))
			tm_type = 3;

		else
			tm_type = -1;
	}

	switch (tm_type) {
		case 0:
			tm_name = "xfov";
			break;
		case 1:
			tm_name = "xmag";
			break;
		case 2:
			tm_name = "zfar";
			break;
		case 3:
			tm_name = "znear";
			break;

		default:
			tm_name = "";
			break;
	}

	if (tm_name.size()) {
		if (axis_name[0])
			return tm_name + "." + std::string(axis_name);
		else 
			return tm_name;
	}

	return std::string("");
}
std::string AnimationExporter::get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
{
	std::string tm_name;
	// when given rna_path, determine tm_type from it
	if (rna_path) {
		char *name = extract_transform_name(rna_path);

		if (!strcmp(name, "color"))
			tm_type = 1;
		else if (!strcmp(name, "spot_size"))
			tm_type = 2;
		else if (!strcmp(name, "spot_blend"))
			tm_type = 3;
		else if (!strcmp(name, "distance"))
			tm_type = 4;
		else
			tm_type = -1;
	}

	switch (tm_type) {
		case 1:
			tm_name = "color";
			break;
		case 2:
			tm_name = "fall_off_angle";
			break;
		case 3:
			tm_name = "fall_off_exponent";
			break;
		case 4:
			tm_name = "blender/blender_dist";
			break;

		default:
			tm_name = "";
			break;
	}

	if (tm_name.size()) {
		if (axis_name[0])
			return tm_name + "." + std::string(axis_name);
		else 
			return tm_name;
	}

	return std::string("");
}
void AnimationExporter::export_morph_animation(Object *ob)
{ 
	FCurve *fcu;
	char *transformName;
	Key *key = BKE_key_from_object(ob);
	if (!key) return;

	if (key->adt && key->adt->action) {
		fcu = (FCurve *)key->adt->action->curves.first;
		
		while (fcu) {
			transformName = extract_transform_name(fcu->rna_path);

			dae_animation(ob, fcu, transformName, true);
			
			fcu = fcu->next;
		}
	}

}
void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
{
	FCurve *fcu = (FCurve *)ob->adt->action->curves.first;

	for (; fcu; fcu = fcu->next) {
		if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix)))
			continue;

		char *name = extract_transform_name(fcu->rna_path);
		if (!strcmp(name, tm_name)) {
			for (unsigned int i = 0; i < fcu->totvert; i++) {
				float f = fcu->bezt[i].vec[1][0];
				if (std::find(fra.begin(), fra.end(), f) == fra.end())   
					fra.push_back(f);
			}
		}
	}

	// keep the keys in ascending order
	std::sort(fra.begin(), fra.end());
}
// Assign sid of the animated parameter or transform 
// for rotation, axis name is always appended and the value of append_axis is ignored
std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
{
	std::string tm_name;
	bool is_rotation = false;
	// when given rna_path, determine tm_type from it
	if (rna_path) {
		char *name = extract_transform_name(rna_path);

		if (!strcmp(name, "rotation_euler"))
			tm_type = 0;
		else if (!strcmp(name, "rotation_quaternion"))
			tm_type = 1;
		else if (!strcmp(name, "scale"))
			tm_type = 2;
		else if (!strcmp(name, "location"))
			tm_type = 3;
		else if (!strcmp(name, "specular_hardness"))
			tm_type = 4;
		else if (!strcmp(name, "specular_color"))
			tm_type = 5;
		else if (!strcmp(name, "diffuse_color"))
			tm_type = 6;
		else if (!strcmp(name, "alpha"))
			tm_type = 7;
		else if (!strcmp(name, "ior"))
			tm_type = 8;

		else
			tm_type = -1;
	}

	switch (tm_type) {
		case 0:
		case 1:
			tm_name = "rotation";
			is_rotation = true;
			break;
		case 2:
			tm_name = "scale";
			break;
		case 3:
			tm_name = "location";
			break;
		case 4:
			tm_name = "shininess";
			break;
		case 5:
			tm_name = "specular";
			break;
		case 6:
			tm_name = "diffuse";
			break;	
		case 7:
			tm_name = "transparency";
			break;	
		case 8:
			tm_name = "index_of_refraction";
			break;	

		default:
			tm_name = "";
			break;
	}

	if (tm_name.size()) {
		if (is_rotation)
			return tm_name + std::string(axis_name) + ".ANGLE";
		else
		if (axis_name[0])
			return tm_name + "." + std::string(axis_name);
		else
			return tm_name;
	}

	return std::string("");
}
// called for each exported object
void AnimationExporter::operator()(Object *ob)
{
	FCurve *fcu;
	char *transformName;
	/* bool isMatAnim = false; */ /* UNUSED */

	//Export transform animations
	if (ob->adt && ob->adt->action) {
		fcu = (FCurve *)ob->adt->action->curves.first;

		//transform matrix export for bones are temporarily disabled here.
		if (ob->type == OB_ARMATURE) {
			bArmature *arm = (bArmature *)ob->data;
			for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next)
				write_bone_animation_matrix(ob, bone);
		}

		while (fcu) {
			//for armature animations as objects
			if (ob->type == OB_ARMATURE)
				transformName =  fcu->rna_path;
			else 
				transformName = extract_transform_name(fcu->rna_path);

			if ((!strcmp(transformName, "location") || !strcmp(transformName, "scale")) ||
			    (!strcmp(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) ||
			    (!strcmp(transformName, "rotation_quaternion")))
			{
				dae_animation(ob, fcu, transformName, false);
			}
			fcu = fcu->next;
		}

	}

	//Export Lamp parameter animations
	if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) {
		fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
		while (fcu) {
			transformName = extract_transform_name(fcu->rna_path);

			if ((!strcmp(transformName, "color")) || (!strcmp(transformName, "spot_size")) ||
			    (!strcmp(transformName, "spot_blend")) || (!strcmp(transformName, "distance")))
			{
				dae_animation(ob, fcu, transformName, true);
			}
			fcu = fcu->next;
		}
	}

	//Export Camera parameter animations
	if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action) {
		fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
		while (fcu) {
			transformName = extract_transform_name(fcu->rna_path);

			if ((!strcmp(transformName, "lens")) ||
			    (!strcmp(transformName, "ortho_scale")) ||
			    (!strcmp(transformName, "clip_end")) || (!strcmp(transformName, "clip_start")))
			{
				dae_animation(ob, fcu, transformName, true);
			}
			fcu = fcu->next;
		}
	}

	//Export Material parameter animations.
	for (int a = 0; a < ob->totcol; a++) {
		Material *ma = give_current_material(ob, a + 1);
		if (!ma) continue;
		if (ma->adt && ma->adt->action) {
			/* isMatAnim = true; */
			fcu = (FCurve *)ma->adt->action->curves.first;
			while (fcu) {
				transformName = extract_transform_name(fcu->rna_path);

				if ((!strcmp(transformName, "specular_hardness")) || (!strcmp(transformName, "specular_color")) ||
				    (!strcmp(transformName, "diffuse_color")) || (!strcmp(transformName, "alpha")) ||
				    (!strcmp(transformName, "ior")))
				{
					dae_animation(ob, fcu, transformName, true, ma);
				}
				fcu = fcu->next;
			}
		}

	}
}