/*
    Copyright (C) 2011 Jaume Singla Valls (jaume dot singlavalls at gmail dot com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "Pictures.h"

#define _USE_MATH_DEFINES
#include <math.h>

#include <SDL_rotozoom.h>
#include <boost/shared_ptr.hpp>

using boost::shared_ptr;

using namespace spcore;
using namespace mod_sdl;
using namespace std;


namespace Pictures {
	
	PicturesTransition::PicturesTransition(){
		this->m_status=0;
		this->m_result=CTypeSDLSurface::CreateInstance();
		this->m_name="identity";
	}
	
	PicturesTransition::PicturesTransition(shared_ptr<PictureNode> Normal){
		this->m_Normal=Normal;
		this->m_status=0;
		this->m_result=CTypeSDLSurface::CreateInstance();
		this->m_name="identity";
	}
	
	PicturesTransition::~PicturesTransition(){
	};
	
	void PicturesTransition::setStatus(float status){m_status=status;};
	
	void PicturesTransition::setCoordinates(int x, int y){
		SDL_Surface* tmp=m_Normal->getBase()->getSurface();
		m_result->setX((short)(x-tmp->w/2));
		m_result->setY((short)(y-tmp->h/2));
	}
	
	void PicturesTransition::applyTransition(){}
	
	void PicturesTransition::reescale(int w, int h){
		w=w;
		h=h;
		SDL_Surface* tmp=m_Normal->getBase()->getSurface();
		tmp=SDL_DisplayFormatAlpha(tmp);
		m_result->setSurface(tmp);
	};
	
	float PicturesTransition::increase(float i){
		m_status+=i;

		if (m_status>1.0f) m_status=1.0f;
		else if (m_status<0.0f) m_status=0.0f;
		
		this->applyTransition();
		
		return m_status;
	}
	
	void applyTransition(){};
	
	float PicturesTransition::getStatus(){ return m_status;};
	
	SmartPtr<CTypeSDLSurface> PicturesTransition::getTransition(){return m_result;}
	
	AlphaTransition::AlphaTransition(shared_ptr<PictureNode> Normal):PicturesTransition(Normal){
		this->m_name="Alpha";
	}
	
	AlphaTransition::~AlphaTransition(){}
	
	void AlphaTransition::applyTransition(){
		SDL_Surface* nova= SDL_DisplayFormatAlpha(m_Normal->getBase()->getSurface());
		// CHECK THIS: value of m_status must be between 0 and 1, otherwise result won't fit into Uint8
		assert (m_status>= 0 && m_status<= 1.0f);
		SDL_gfxMultiplyAlpha2(nova, m_status*255);
		this->m_result->setSurface(nova);
	}
	
	ScaleTransition::ScaleTransition(shared_ptr<PictureNode> Normal):PicturesTransition(Normal){
		this->m_originalx=0;
		this->m_originaly=0;
		this->m_name="scale";
	}
	
	ScaleTransition::~ScaleTransition(){
	}
	
	void ScaleTransition::setCoordinates(int x, int y){
		this->m_originalx=x;
		this->m_originaly=y;
	}
	
	void ScaleTransition::applyTransition(){
		SDL_Surface* nova=zoomSurface(m_Normal->getBase()->getSurface(), m_status, m_status, 0);

		this->m_result->setX(this->m_originalx-nova->w/2);
		this->m_result->setY(this->m_originaly-nova->h/2);
		
		this->m_result->setSurface(nova);
	}
	
	RotateTransition::RotateTransition(shared_ptr<PictureNode> Normal, int degree):PicturesTransition(Normal){
		m_degree=degree;
		this->m_name="rotate";
	}
	
	RotateTransition::~RotateTransition(){};
	
	void RotateTransition::setCoordinates(int x, int y){
		this->m_originalx=x;
		this->m_originaly=y;
	}
	
	void RotateTransition::applyTransition(){
		SDL_Surface* nova=rotozoomSurface(m_Normal->getBase()->getSurface(), m_status*m_degree, 1, 0);

		this->m_result->setX(this->m_originalx-nova->w/2);
		this->m_result->setY(this->m_originaly-nova->h/2);
		this->m_result->setSurface(nova);
	}
	
	ChangePictureTransition::ChangePictureTransition(shared_ptr<PictureNode> Normal,SmartPtr<mod_sdl::CTypeSDLSurface> surf):PicturesTransition(Normal){
		m_original = surf;
		m_Base=CTypeSDLSurface::CreateInstance();;
		m_old_w=0;
		m_old_h=0;
		this->m_name="Change";
	}
	
	ChangePictureTransition::~ChangePictureTransition(){
	}
	
	void ChangePictureTransition::applyTransition(){
		SDL_Surface* nova;
		if(m_Base->getSurface()!=NULL){
			if (m_status<0.5f){
				nova= SDL_DisplayFormatAlpha(m_Base->getSurface());
			} else {
				nova= SDL_DisplayFormatAlpha(m_Normal->getBase()->getSurface());
			}
			this->m_result->setSurface(nova);
		}
	}
	
	void ChangePictureTransition::reescale(int w, int h){
		if (m_old_w!=w || m_old_h!=h){

			// BUG: when transition destination image is not found in the XML
			// this code crashed, we now assert and provide a workaround
			// use error_reproduce/error_1.xml. PROVIDE A FIX
			assert (m_original.get() && m_original->getSurface() && m_original->getSurface()->w);

			// Workaround
			if (m_original.get()) {
				double scalex=(((float) w)/1920.0f)*(m_Normal->getScale()/0.25f)*(((float)500)/ (float)m_original->getSurface()->w);
			
				SDL_Surface* tmp=zoomSurface(m_original->getSurface(), scalex, scalex,0);
				m_Base->setSurface(tmp);
				PicturesTransition::reescale(w,h);
				m_old_w=w; m_old_h=h;
			}
		}
		
	}
	
	TranslatePictureTransition::TranslatePictureTransition(shared_ptr<PictureNode> normal, float px, float py): PicturesTransition(normal){
		m_orig_x=px;
		m_orig_y=py;
		m_old_w=0;
		m_old_h=0;
		m_dstInt_x=0;
		m_dstInt_y=0;
		m_origInt_x=0;
		m_origInt_y=0;
		this->m_name="Translate";
	}
	
	TranslatePictureTransition::~TranslatePictureTransition(){}
	
	void TranslatePictureTransition::setCoordinates(int x, int y){
		m_dstInt_x=x;
		m_dstInt_y=y;
	}
	
	void TranslatePictureTransition::applyTransition(){
		int vx,vy;
		if (m_result->getSurface()!=NULL){

			/*
			 * It uses the position calculated in the reescale method, makes a integer vector for the "translate vector" and apply the part related to the status.
			 */
			vx=m_dstInt_x-m_origInt_x;
			vy=m_dstInt_y-m_origInt_y;

			m_result->setX(m_origInt_x+vx*m_status-m_result->getSurface()->w/2);
			m_result->setY(m_origInt_y+vy*m_status-m_result->getSurface()->h/2);
		}
	}
	
	void TranslatePictureTransition::reescale(int w, int h){
		if (m_old_w!=w || m_old_h!=h){
			PicturesTransition::reescale(w,h);

			m_origInt_x=w*(m_orig_x-0.5f)+w/2;
			m_origInt_y=w*(m_orig_y-0.5f)+h/2;
			m_old_w=w; m_old_h=h;
		}
	}
	
	
	VibratePackagePictureTransition::VibratePackagePictureTransition(shared_ptr<PicturesTransition> transition, float percent):PicturesTransition(){
		m_transition=transition;
		m_percent=percent;
		m_quantity=4;
	}
	
	VibratePackagePictureTransition::~VibratePackagePictureTransition(){
	}
	
	void VibratePackagePictureTransition::applyTransition(){
		m_transition->setStatus(1-m_percent+m_percent*sin(this->m_status*m_quantity * (float) M_PI)/2 +m_percent/2);
		
		m_transition->applyTransition();
		this->m_name="Vibrate";
		
	}
	
	void VibratePackagePictureTransition::setCoordinates(int x, int y){
		m_transition->setCoordinates(x,y);
	}
	
	void VibratePackagePictureTransition::reescale(int x, int y){
		m_transition->reescale(x,y);
	}
	
	SmartPtr<mod_sdl::CTypeSDLSurface> VibratePackagePictureTransition::getTransition(){
		return m_transition->getTransition();
	}
}