/*
 * Copyright (c) 2008-2009 Bill Whitacre http://rampancy.g0dsoft.com
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
*/

#include "common.h"
#include "area.h"
#include "inertia.h"

rat_block_allocator *rat_global_block_allocator=NULL;
static int is_physics_engine_init=0;

int rat_physics_is_init()
{
	return is_physics_engine_init;
}

static int ___free_global_bal()
{
	if (rat_global_block_allocator)
	{
		rat_block_allocator_destroy(rat_global_block_allocator);
		rat_global_block_allocator=NULL;
		return 1;
	}
	else
		return 0;
}

static void ___atexit__cleanup(void)
{
	if (!rat_physics_cleanup())
	{
		fprintf(stderr,"Rat Physics cleanup at process exit failed!\n");
		fflush(stderr);
	}
}

int rat_physics_init()
{
	if (!is_physics_engine_init)
	{
		rat_global_block_allocator=rat_block_allocator_create();
		if (!rat_global_block_allocator) return 0;

		atexit(&___atexit__cleanup);
		is_physics_engine_init=1;
	}
	return 1;
}

int rat_physics_cleanup()
{
	if (is_physics_engine_init)
	{
		if (!___free_global_bal()) return 0;
		is_physics_engine_init=0;
	}
	return 1;
}

void rat_iterator_next(rat_iterator *iter)
{
	iter->clas->next(iter);
}

int rat_iterator_finished(rat_iterator *iter)
{
	return iter->clas->finished(iter);
}

void *rat_iterator_value(rat_iterator *iter)
{
	return iter->clas->value(iter);
}

void rat_iterator_destroy(rat_iterator *iter)
{
	iter->clas->destroy(iter);
}

// handy floating point op inlines

rat_real rat_clampf(rat_real x,rat_real max,rat_real min)
{
	return (x=x>max?max:x)<min?min:x;
}

rat_real rat_maxf(rat_real x,rat_real max)
{
	return x>max?max:x;
}

rat_real rat_minf(rat_real x,rat_real min)
{
	return x<min?min:x;
}

rat_real rat_area_particle()
{
	return 0;
}

rat_real rat_area_circle(rat_real radius)
{
	return MATH_PI*radius*radius;
}

rat_real rat_area_polygon(vector2 *pts,unsigned int numsides)
{
	register unsigned int i;
	register rat_real area=0.0;

	for (i=0; i<numsides; i++)
	{
		register rat_real base;
		register rat_real height;

		base=vector2_magnitude(pts[i]);
		height=vector2_distance(vector2_project(pts[(i+1)%numsides],pts[i]),pts[i]);

		area+=(base*height)/2.0;
	}

	return area;
}

rat_real rat_moi_particle(rat_real mass)
{
	return 0;
}

rat_real rat_moi_circle(rat_real mass,rat_real radius)
{
	return radius>0?mass*(radius*radius)/2.0:0;
}

rat_real rat_moi_polygon(rat_real mass,vector2 *pts,unsigned int numsides)
{
	register unsigned int i;

	register rat_real sumtop=0.0;
	register rat_real sumbot=0.0;

	for (i=0; i<numsides; i++)
	{
		vector2 va=pts[i];
		vector2 vb=pts[(i+1)%numsides];

		rat_real a=vector2_cross(vb,va);
		rat_real b=vector2_dot(va,va)+vector2_dot(va,vb)+vector2_dot(vb,vb);

		sumtop+=a*b;
		sumbot+=a;
	}

	return (mass*sumtop)/(6.0*sumbot);
}

