#ifndef _IMAGE_BRUSH_H
#define _IMAGE_BRUSH_H

#include "ofMain.h"
#include "ofAddons.h"

class imageBrush{
	
	public: 
		
		//------------------------
		imageBrush(){			
			
			strokeSpeed = 0;
			
			numBrushes  = 0;
			brush		= -1;
		}
		
		//------------------------
		void setup(int _width, int _height){
		
			width  			= _width;
			height 			= _height;
			imageNumBytes 	= 3;		
			
			oldX			= 0;
			oldY			= 0;
			
			//default to white
			red				= 255;
			green			= 255;
			blue			= 255;	

			pixels = new unsigned char[width * height * imageNumBytes];
			clear();
		}
		
		//------------------------
		void clear(){
			memset(pixels, 0, width*height*imageNumBytes);
		}
		
		//reads a directoty for png files
		//loads them into imageBrush as the different brushes
		//format should be b&w 32 by 32 png with white being the 
		//brush shape
		//------------------------
		int loadBrushes(string brushDir){
			
			DL.allowExt("png");
			numBrushes = DL.listDir(brushDir);
			
			printf("num brushed are %i \n", numBrushes);
			
			//set a default brush
			if(numBrushes > 0){
				brush = 0;
				selectBrush(brush);
			}
			
			return numBrushes;
		}
		
		//-----------------------------------------------------		
		int selectBrush(int _num){

			if(numBrushes == 0)return 0;
		
			if(_num >= numBrushes){
				_num = numBrushes-1;
			}
			
			brush = _num;
						
			IMG.loadImage(DL.getPath(brush));
			
			 //no need for color
			 //we will use the image as a mask to 
			 //draw with and multiply it with
			 //our drawing color.
			IMG.setImageType(OF_IMAGE_GRAYSCALE); 
			updateTmpImage(brushSize);

			return brush;			
		}
		
		//-----------------------------------------------------
		void updateTmpImage(float _brushSize){
			
			TMP.clone(IMG);
			
			float tmpW 		= TMP.width;
			float tmpH 		= TMP.height;
			
			float ratio 	= (float)_brushSize/tmpW;
				
			int newWidth  	= _brushSize;
			int newHeight  	= tmpH*ratio;
			
			TMP.resize(newWidth, newHeight);
		}
		
		//-----------------------------------------------------
		void setColor(unsigned char r, unsigned char g, unsigned char b){
			red		= r;
			green	= g;
			blue 	= b;
		}
		
		//-----------------------------------------------------
		string getBrushName(){
			return DL.getName(brush);
		}
		
		//-----------------------------------------------------
		bool paint(float _x, float _y, int _brushSize, int _numSteps, bool newStroke){
						
			if(brush < 0){
				return false;
			}
						
			//only resize the brush when its size has changed
			if(brushSize != _brushSize){		
				brushSize = _brushSize;
				updateTmpImage(_brushSize);
			}
			
			//calc some info for where to draw from						
			int pix			= 0;
			int stride 		= width*imageNumBytes;
			int startX 		= _x;
			int startY 		= _y;
			int numSteps 	= _numSteps;
			
			int tx, ty;
			float dx, dy;
					
			if(newStroke){
				numSteps = 1;	//then just one image
				oldX = startX;
				oldY = startY;
			}else{
				dx = ((float)(startX - oldX)/numSteps);
				dy = ((float)(startY - oldY)/numSteps);
			}
			
			//get the pixels of the brush
			unsigned char * brushPix = TMP.getPixels();
			
			// lets draw the brush many times to make a line
			for(int i = 0; i < numSteps; i++){				
							
				// we do - TMP.width/2 because we want the brush to be
				// drawn from the center
				if(newStroke){
					tx = startX - TMP.width/2;
					ty = startY - TMP.height/2;
				}else{
					tx = (oldX + (int)(dx*i)) - TMP.width/2;
					ty = (oldY + (int)(dy*i)) - TMP.height/2;
				}
				
				//this is what we use to move through the
				//brush array									
				int tPix = 0;
				
				int destX = (TMP.width  + tx);
				int destY = (TMP.height + ty);	
								
				//lets check that we don't draw out outside the projected
				//image
				if(destX >= width)   destX = width  -1;
				if(destY >= height)  destY = height -1;
				
				//if the brush is a bit off the screen on the left side
				//we need to figure this amount out so we only copy part
				//of the brush image 
				int offSetCorrectionLeft = 0;	
				if(tx < 0){
					offSetCorrectionLeft = -tx;
					tx = 0;
				}
				
				//same here for y - we need to figure out the y offset
				//for the cropped brush
				if(ty < 0){
					tPix    = -ty * TMP.width; 
					ty 		= 0;
				}
								
				//this is for the right hand side cropped brush 
				int offSetCorrectionRight = ((TMP.width + tx) -  destX);	

					tPix += offSetCorrectionLeft;

				//some vars we are going to need
				//put here to optimise? 
				float r, g, b, value, ival;

				for(int y = ty; y < destY; y++){
					for(int x = tx; x < destX; x++){
							
						pix = x*imageNumBytes + (y*stride);
						
						if(brushPix[tPix] == 0){
							//we don't need to do anything
							tPix++;
							continue;
						}						
						//okay so here we are going to use the pixel value of the brush
						//as a multiplier to add into the image
						value = (float)brushPix[tPix]/255;
						ival  = 1.0 - value;
						
						r 	= (float)pixels[pix  ] * ival + red   * value;
						g 	= (float)pixels[pix+1] * ival + green * value;
						b 	= (float)pixels[pix+2] * ival + blue  * value;
						
						pixels[pix  ] = (unsigned char)r;
						pixels[pix+1] = (unsigned char)g;
						pixels[pix+2] = (unsigned char)b;
																													
						tPix++;					
					}
					tPix += offSetCorrectionRight;
				}
			
			}
			
			oldX = startX;
			oldY = startY;
									
			return true;
		}
			
		//-----------------------------------------------------
		unsigned char * getPixels(){
			return pixels;
		}
		
		//-----------------------------------------------------
		void drawBrush(float x, float y, int w, int h){
			IMG.draw(x,y,w,h);
		}
		
	
	
	protected:
	
		ofDirList DL;
	
		ofImage IMG;
		ofImage TMP;
			
		unsigned char * pixels;
	
		int oldX, oldY, width, height, brush, numBrushes, brushSize, imageNumBytes;
	
		float red, green, blue;
		float strokeSpeed;

};



#endif
