#include "Terrain.h"

Terrain::Terrain()
: m_size( 0 ), m_multi(MULTI), m_plot( 0x0 ), m_areaBody( 0x0 ),
m_minX( 0.0f ), m_minY( 0.0f ), m_maxX( 0.0f ), m_maxY( 0.0f ),
m_backTexture( 0x0 ), m_groundTexture( 0x0 ), m_bricks( 0x0 ), m_buff1( 0x0 ), m_buff2( 0x0 )
{
	// Constructor
}

Terrain::~Terrain()
{
	// Points
	if ( m_plot )
	{
		delete[] m_plot ;
		m_plot = 0x0 ;
	}

	// Textures
	if ( m_groundTexture )
	{
		SDL_FreeSurface( m_groundTexture );
		m_groundTexture = 0x0;
	}

	if ( m_backTexture )
	{
		SDL_FreeSurface( m_backTexture );
		m_backTexture = 0x0;
	}

	// Buffers
	if ( m_buff1 )
	{
		SDL_FreeSurface( m_buff1 );
		m_buff1 = 0x0;
	}

	if ( m_buff2 )
	{
		SDL_FreeSurface( m_buff2 );
		m_buff2 = 0x0;
	}

	if ( m_bricks )
	{
		SDL_FreeSurface( m_bricks );
		m_bricks = 0x0;
	}
}

void Terrain::defaultPlot()
{
	// Safety
	if ( m_plot )
	{
		std::cout << "Données déjà existantes ; échec Terrain::defaultPlot()." << std::endl;
		return;
	}

	// Tableau
	m_size = 400;
    m_plot = new b2Vec2[m_size];

	// Premiers points
	m_plot[0].x = 0.0f;
	m_plot[0].y = 0.0f;

    m_plot[1].x = 0.0f;
    m_plot[1].y = 2.75f;

	// Remplissage
	for ( unsigned int i(2); i < m_size; i++ )
	{
		m_plot[i].x = 1.0f * i;
		m_plot[i].y = 2.75f + 1.2f * sin( 0.05f * std::pow( i, 1.35f ) );
	}
}

void Terrain::build( b2World &world )
{
	// Check previous body
	if ( m_areaBody )
	{
		world.DestroyBody( m_areaBody );
		m_areaBody = nullptr;
	}

	// Build fixture
	b2BodyDef areaDef;
	areaDef.position.Set(0.0f, 0.0f);
	m_areaBody = world.CreateBody(&areaDef);

	b2ChainShape chain;
	b2Vec2 prev(m_plot[0]), next(m_plot[m_size - 1]);
	chain.CreateChain( m_plot, m_size, prev, next );
	m_areaBody->CreateFixture( &chain, 0.0f );
}

void Terrain::textureLoad( SDL_Surface* screen )
{
	// Load texture ground
	if ( m_groundTexture == 0x0 )
		m_groundTexture = IMG_Load( "Textures/brick052b.jpg" );

	if ( m_groundTexture == 0x0 )
		std::cout << "Texture " << "Textures/brick052b.jpg" << " impossible à charger." << std::endl;

	// Load texture background
	if ( m_backTexture == 0x0 )
		m_backTexture = IMG_Load( "Textures/ChatoLine.jpg" );

	if ( m_backTexture == 0x0 )
		std::cout << "Texture " << "Textures/ChatoLine.jpg" << " impossible à charger." << std::endl;

	// Create buffers
	if ( m_buff1 == 0x0 )
		m_buff1 = SDL_CreateRGBSurface( SDL_HWSURFACE, screen->w, screen->h, 32, 0, 0, 0, 0);

	SDL_SetColorKey( m_buff1, SDL_SRCCOLORKEY, SDL_MapRGB(screen->format, 0, 0, 0) );// 255 128 0

	if ( m_buff2 == 0x0 )
		m_buff2 = SDL_CreateRGBSurface( SDL_HWSURFACE, screen->w, screen->h, 32, 0, 0, 0, 0);

	if ( m_bricks == 0x0 )
		m_bricks = SDL_CreateRGBSurface( SDL_HWSURFACE, screen->w, screen->h, 32, 0, 0, 0, 0);

	// Fill up bricks
	if ( m_groundTexture == 0x0 )
		return;

	SDL_Rect pos({0, 0, 0, 0});

	for ( pos.y = 0; pos.y < screen->h; pos.y += m_groundTexture->h )
		for ( pos.x = 0; pos.x < screen->w; pos.x += m_groundTexture->w )
			SDL_BlitSurface( m_groundTexture, 0x0, m_bricks, &pos );

	// Optimisation
	accelerateTexture( m_backTexture );
	accelerateTexture( m_groundTexture );
	accelerateTexture( m_bricks );
	accelerateTexture( m_buff1 );
	accelerateTexture( m_buff2 );
}

void Terrain::accelerateTexture( SDL_Surface* & text )
{
	if ( !text )
		return;

	SDL_Surface* temp( text );

	text = SDL_DisplayFormat( temp );

	SDL_FreeSurface( temp );
}

void Terrain::draw( SDL_Surface* screen, b2Vec2 origin )
{
	Sint16 xTab[4];
	Sint16 yTab[4];

	for ( unsigned int i(0); i < m_size - 1 ; i++ )
	{
		xTab[0] = xTab[3] = ( m_plot[i].x - origin.x ) * m_multi ;
		xTab[1] = xTab[2] = ( m_plot[i + 1].x - origin.x ) * m_multi ;

		if ( ! (xTab[1] > 0 && xTab[0] < screen->w ) )
			continue ;

		yTab[0] = ( m_plot[i].y - origin.y ) * m_multi ;
		yTab[1] = ( m_plot[i + 1].y - origin.y ) * m_multi ;

		yTab[2] = screen->h;
		yTab[3] = screen->h;

		filledPolygonRGBA( screen, xTab, yTab, 4, 255, 0, 0, 255);
	}
}

void Terrain::drawUni( SDL_Surface* screen, b2Vec2 origin )
{
	// Variables
	m_vx.clear();
	m_vy.clear();
	Sint16 x, y;

	// Incrément
	unsigned int i(1);

	// Recherche du premier point dans le champ
	while ( m_plot[i].x < origin.x )
		i ++;

	// Revenir au dernier point hors champ
	i --;

	// Premiers points du polygone
	x = ( m_plot[i].x - origin.x ) * m_multi;

	m_vx.push_back( x );
	m_vy.push_back( screen-> h );

	// Ajout des points visibles
	for ( ; i < m_size && m_vx.back() < screen->w ; i++ )
	{
		x = ( m_plot[i].x - origin.x ) * m_multi;
		y = ( m_plot[i].y - origin.y ) * m_multi ;

		m_vx.push_back( x );
		m_vy.push_back( y );
	}

	// Ajout du dernier point
	m_vx.push_back( x );
	m_vy.push_back( screen-> h );

	// Dessin
	filledPolygonRGBA( screen, m_vx.data(), m_vy.data(), m_vx.size(), 255, 128, 0, 255 );
}



void Terrain::drawWithTexture( SDL_Surface* screen, b2Vec2 origin )
{
	// Load texture
	if ( m_groundTexture == 0x0 )
		drawUni( screen, origin );

	// Variables
	m_vx.clear();
	m_vy.clear();
	Sint16 x, y;

	// Incrément
	unsigned int i(0);

	// Recherche du premier point dans le champ
	while ( m_plot[i].x < origin.x )
		i ++;

	// Revenir au dernier point hors champ
	//i --;

	// Premiers points du polygone
	x = ( m_plot[i].x - origin.x ) * m_multi;

	m_vx.push_back( x );
	m_vy.push_back( screen-> h - 5 );

	// Ajout des points visibles
	for ( ; i < m_size && m_vx.back() < screen->w ; i++ )
	{
		x = ( m_plot[i].x - origin.x ) * m_multi;
		y = ( m_plot[i].y - origin.y ) * m_multi ;

		m_vx.push_back( x );
		m_vy.push_back( y );
	}

	// Debug
	m_vx.pop_back();
	m_vy.pop_back();

	// Ajout du dernier point
	m_vx.push_back( ( m_plot[i - 2].x - origin.x ) * m_multi );
	m_vy.push_back( screen-> h - 5 );

	// Dessin
	texturedPolygon( screen, m_vx.data(), m_vy.data(), m_vx.size(), m_groundTexture, -origin.x * m_multi, origin.y * m_multi);
	polygonRGBA( screen, m_vx.data(), m_vy.data(), m_vx.size(), 255, 0, 0, 255 );
}

void Terrain::drawArtist( SDL_Surface* screen, b2Vec2 origin )
{
	// Process first buffer
	SDL_Rect pos;
	pos.x = - ( origin.x - m_minX ) * ( m_backTexture->w - screen->w ) / ( m_maxX - m_minX );
	pos.y = - ( origin.y - m_minY ) * ( m_backTexture->h - screen->h ) / ( m_maxY - m_minY );
	//SDL_FillRect(m_buff1, 0, 0x00000000 );
	SDL_BlitSurface( m_backTexture, 0x0, screen, & pos );
	drawUni( screen, origin );

	// Process second buffer
	/*SDL_BlitSurface( m_bricks, 0x0, m_buff2, 0x0 );
	SDL_BlitSurface( m_buff1, 0x0, m_buff2, 0x0 );*/

	// Final rendering
	//SDL_BlitSurface( m_buff2, 0x0, screen, 0x0 );
}

void Terrain::load(std::string chemin)
{
	// Flux
    std::ifstream loadStream( chemin.c_str() );

    // Lecture
    float buff;

    std::vector<float> data;

    while ( loadStream >> buff )
		data.push_back( buff );

	loadStream.close();

	// Remplacment
	if ( m_plot )
	{
		delete[] m_plot;
		m_plot = 0x0;
	}

	// Création
	m_size = data.size() / 2;
	m_plot = new b2Vec2[m_size];

	// Remplissage
	for ( unsigned int i(0); i < m_size; i++ )
	{
		m_plot[i].x = data[2*i];
		m_plot[i].y = data[2*i + 1];
	}

	// Ajustement du scrolling
	setMaxRect();
}

void Terrain::setMaxRect()
{
	// Réinitialisation
	m_maxX = m_minX = m_maxY = m_minY = 0.0f;

	// Recherche des extremums
	for ( unsigned int i(0); i < m_size; i++ )
	{
		if ( m_plot[i].x > m_maxX )
			m_maxX = m_plot[i].x;

		if ( m_plot[i].x < m_minX )
			m_minX = m_plot[i].x;

		if ( m_plot[i].y > m_maxY )
			m_maxY = m_plot[i].y;

		if ( m_plot[i].y < m_minY )
			m_minY = m_plot[i].y;
	}

	// Ajustements
	m_minY -= 6.0f;
}


void Terrain::setMulti( float newMulti )
{
	m_multi = newMulti;

	if ( m_multi <= 0.0f )
		m_multi = MULTI;
}


/// END OF FILE