/*
    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"

#include <iostream>

#include "SDL_rotozoom.h"
//#include "SDL_gfxBlitFunc.h"

using namespace std;
using namespace mod_sdl;

namespace Pictures{
	
	/* 
	 *	Extract from file SDL_gfxBlitFunc of SDL_gfx library with LGPL (c) and author A. Schiffler
	 *
	 *	We need this for problems with the actual version of the library, it don't implement this.
	 *	The original Name is SDL_gfxMultiplyAlpha
	 */
	
	int SDL_gfxMultiplyAlpha2(SDL_Surface *src, Uint8 a)
	{
	#if SDL_BYTEORDER == SDL_BIG_ENDIAN
		Uint16 alpha_offset = 0;
	#else
		Uint16 alpha_offset = 3;
	#endif
		Uint16 i, j;
	
		/* Check if we have a 32bit surface */
		if ( (src) && (src->format) && (src->format->BytesPerPixel==4) && (a!=255) ) {
			/* Lock and process */
			if ( SDL_LockSurface(src) == 0 ) {
				Uint8 *pixels = (Uint8 *)src->pixels;
				Uint16 row_skip = (src->pitch - (4*src->w));
				pixels += alpha_offset;
				for ( i=0; i<src->h; i++ ) {
					for ( j=0; j<src->w; j++  ) {
						*pixels = (Uint8)(((int)(*pixels)*a)>>8);
						pixels += 4;
					}
					pixels += row_skip;
				}
				SDL_UnlockSurface(src);
			}
			return 1;
		}
	
		return 0;
	}
	
	/*
	 * Constructor of picture node, it inicialize all private vars, and assign the arguments to atributes.
	 * 	* surf : Is original surface, exactly as read from file. (it is copied to the m_Base in reescale, with the size we use)
	 * 	* x: Is the relative position x (float 0..1)
	 * 	* y: Is the relative position y (float 0..1)
	 * 	* scale: Is the relative size from the window size. 
	 */
	PictureNode::PictureNode(SmartPtr<const mod_sdl::CTypeSDLSurface> surf, float x, float y, float scale){
		this->m_original=surf;
		this->m_x=x;
		this->m_y=y;
		this->m_alpha=255;
		this->m_status=1;
		this->m_scale=scale;
		this->m_Base=CTypeSDLSurface::CreateInstance();;
	}

	/*
	 * Constructor of picture node, it inicialize all private vars, and assign the arguments to atributes, it has the new atribute the size of the window.
	 * 	* surf : Is original surface, exactly as read from file. (it is copied to the m_Base in reescale, with the size we use)
	 * 	* x: Is the relative position x (float 0..1)
	 * 	* y: Is the relative position y (float 0..1)
	 * 	* scale: Is the relative size from the window size.
	 * 	* Width: It is the window size x
	 * 	* height: It is the window size y
	 */
	PictureNode::PictureNode(SmartPtr<const mod_sdl::CTypeSDLSurface> surf, float x, float y, float scale, int width, int height){
		this->m_original=surf;
		this->m_x=x;
		this->m_y=y;
		this->m_alpha=255;
		this->m_status=1;
		this->m_scale=scale;
		this->m_Base=CTypeSDLSurface::CreateInstance();;
		this->rescale(width, height);
	}
	
	/*
	 * Free the object and his attributes
	 */
	PictureNode::~PictureNode(){
	}
	
	/*
	 * Assign the input transition, (the name is based on collage kernel, this transition will be executed when the picture appear in collage)
	 */
	void PictureNode::setTransitionIn(boost::shared_ptr<PicturesTransition> in, float status){
		in->setStatus(status);
		this->m_in=in;
	}
	
	/*
	 * Assign the output transition. (similar as input transition, but this will be executed before the picture disapear, for the action of movement. )
	 * It is not the transition executed when the picture disapear because we don't have movement.
	 */
	void PictureNode::setTransitionOut(boost::shared_ptr<PicturesTransition> out,float status){
		out->setStatus(status);
		this->m_out=out;
	}
	
	/*
	 * Obtain the input transition
	 */
	boost::shared_ptr<PicturesTransition> PictureNode::getTransitionIn(){
		return this->m_in;
	}
	
	/*
	 * Obtain the output transition.
	 */
	boost::shared_ptr<PicturesTransition> PictureNode::getTransitionOut(){
		return this->m_out;
	}
	
	/*
	 * It is for destroy the share_ptr cicle, it only release the transitions, and it causes the destroy of transition.
	 */
	void PictureNode::breakCycle(){
		this->m_in=boost::shared_ptr<PicturesTransition>();
		this->m_out=boost::shared_ptr<PicturesTransition>();
	}
	
	
	/*
	 * It is executed when the picture was created, or when the window size was redimensioned, it copy the base surface, and reescale to the proportional size, always set the new position of the image.
	 * 
	 */
	void PictureNode::rescale(int width, int height){
		double scalex=(((float) width)/1920.0f)*(m_scale/0.25f)*(((float)500)/ (float)m_original->getSurface()->w);

		SDL_Surface* tmp=zoomSurface(const_cast<SDL_Surface *>(m_original->getSurface()), scalex, scalex,0);
		m_Base->setSurface(tmp);
		SDL_gfxMultiplyAlpha2(tmp,m_alpha);

		int absx=width*(m_x-0.5f)+width/2;
		int absy=width*(m_y-0.5f)+height/2;
		
		if (m_in.get()!=NULL){
			m_in->reescale(width, height);
			m_in->setCoordinates(absx, absy);
			m_in->applyTransition();
		}
		if (m_out.get()!=NULL){
			m_out->reescale(width, height);
			m_out->setCoordinates(absx, absy);
			m_out->applyTransition();
		}
	}
	
	/*
	 * It return the scale of the object.
	 */
	float PictureNode::getScale(){
		return m_scale;
	}
	
	/*
	 * It return the picture surface with the proportional size.
	 */
	SmartPtr<mod_sdl::CTypeSDLSurface> PictureNode::getBase(){
		return this->m_Base;
	}
	
	/*
	 * Return the picture with the transition applied.
	 */
	SmartPtr<CTypeSDLSurface> PictureNode::getcType(){
		if (this->m_status!=-1){
			return this->m_in->getTransition();
		} else {
			return this->m_out->getTransition();
		}
	}
	
	
	/*
	 * It is the function that was used when (in the mod_collage) we don't have motion, and we need the pictures disapears.
	 */
	bool PictureNode::decreaseAlpha(){		
		--m_alpha;
		SDL_gfxMultiplyAlpha2(m_Base->getSurface(),254);

		if (this->m_status!=-1)
			this->m_in->applyTransition();
		else
			this->m_out->applyTransition();

		return (m_alpha== 0);
	}
	
	/*
	 * Is used for know if the transition was completed or not.
	 */
	float PictureNode::getStatusTransition(){
		if (this->m_status==0){
			return 1.0f;
		} else if(this->m_status==1){
			return this->m_in->getStatus();
		} else {
			return this->m_out->getStatus();
		}
	}
	
	/*
	 * Execute the input transition, and use the argument for know what percentage of transition was transcurred. 
	 */
	float PictureNode::increaseTransition(float inc){
		if (this->m_in!=NULL){
			float ret=this->m_in->increase(inc);
			if (ret==1){
				this->m_status=0;
			}
			return ret;
		}
		return 1;
	}
	
	/*
	 * Similar as increaseTransition, but for the output transition, it cannot be executed, if we are in the step of increase.
	 */
	float PictureNode::decreaseTransition(float dec){
		if (this->m_out!=NULL && this->m_status<1){
			this->m_status=-1;
			return this->m_out->increase(-dec);
		}
		return 0;
	}

	/*
	 * Return the actual step, {
	 * 	-1 => the picture was executing the output transition,
	 * 	 0 => the picture was in the normal state, it is showing withouth transition effect.
	 * 	 1 => The picture was executing the input transition }
	 */
	int PictureNode::getStatus(){return m_status;};
	
	/*
	 * It can be used for force the step of the picture, using the three values of the getStatus method.
	 */
	void PictureNode::setStatus(int v){m_status=v;};
}
