#ifndef _VECTOR_BRUSH_H
#define _VECTOR_BRUSH_H

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

//inhereit me to draw with the data
//see vectorBrushRaster bellow
class vectorBrush{
	
	public: 
		
		//------------------------
		vectorBrush(){
			dontDraw	= true;
			isSetup 	= false;
			total		= 0;
			strokeSpeed = 0;
		}
		
		//------------------------
		int setupBrush(int numParticles){
		
			//need at least 3 particles
			if(numParticles <= 2 )	return 0;
			
			//if we have already created particles
			if(isSetup){
				delete pos; // kill em
				delete targ;
			}
			
			total = numParticles;
			
			//we always need an odd number of particles
			if(total%2==0){
				total++;
			}
			
			//lets calculate the center particle
			center = (total - 1)/2;
			
			//and half the total amount of particles
			hTotal = (total + 1)/2;
			
			pos			= new ofVec2f[total];
			targ		= new ofVec2f[total];
			
			isSetup 	= true;
			dontDraw	= true;
			
			return total;
		}
		
		
		//------------------------
		void addStroke(float newX, float newY, float brushWidth, bool isNewStroke){
		
			if(isNewStroke){
				//we need at least two points so we don't draw until 
				//then
				dontDraw = true; 
				
				targ[center].x = newX;
				targ[center].y = newY;
				
				return;
			}
			
		
			ofVec2f start;
			ofVec2f dest;
		
			dest.set(newX, newY);
			start = targ[center];
			
			//we need to get the normal (perpindicular) to this line!
			//we do this by calc the dist between the two points then
			//using this normalised vector to make a positive and negative
			//normal
			
			ofVec2f tmpPerp	= dest - start;
			
			//lets grab the distance of the line while the data is there for us
			float distLength 	= tmpPerp.length(); 
			
			if(distLength == 0){
				return;
			}else if(distLength > 14){
				perp = tmpPerp;
			}

			//okay lets normalise
			//this will give us an easy way to calculate the perpendicular to our 
			//line as the normalized normals (whoa!) will be the (-y, x) and (y, -x) of this value 
			perp.normalize();
			
			//this is the first set of points we can use
			if(dontDraw){
							
				int upPos 	= center;
				int dnPos 	= center;
				//lets caluclate the spread amnt between pts based on brushWidth
				float pct 	= (brushWidth - strokeSpeed*brushWidth)  / hTotal;
				float amnt	= 0;
								
				for(int i = 0; i < hTotal; i++){
					if(i == 0){
						pos[center].set(start.x, start.y);
					}else{
					
						//this should create a series of points along a line perpindicular
						//to the stroke.the points should work their way out in either direction
						//away from the center
						pos[upPos].set(start.x + perp.y * amnt, start.y - perp.x * amnt);
						pos[dnPos].set(start.x - perp.y * amnt, start.y + perp.x * amnt);

						 //this is what spreads the points out based on the brushWidth
					} 
					
					amnt += pct;
					upPos++;
					dnPos--;
				}
			}else{
				for(int i = 0; i < total; i++){
					pos[i] = targ[i];
				}
			}
			
			//okay now lets calculate the target as well.
			int upPos 	= center;
			int dnPos 	= center;
			//lets caluclate the spread amnt between pts based on brushWidth
			float tmpStrokeSpeed = distLength * 0.3;
			
			tmpStrokeSpeed /= brushWidth;
			
			if(tmpStrokeSpeed > 1.0) tmpStrokeSpeed = 1.0;
			if(tmpStrokeSpeed < 0.0) tmpStrokeSpeed = 0.0;
			
			//printf("speed is %f \n",tmpStrokeSpeed * 100.0);
			
			strokeSpeed = 1.8 * (tmpStrokeSpeed - 0.5);
			
			
			float pct 	= ( (brushWidth - strokeSpeed*brushWidth) / hTotal);
			float amnt	= 0;
				
			for(int i = 0; i < hTotal; i++){
				if(i == 0){
					targ[center].set(dest.x, dest.y);
				}else{
				
					//this should create a series of points along a line perpindicular
					//to the stroke.the points should work their way out in either direction
					//away from the center
					targ[upPos].set(dest.x + perp.y * amnt, dest.y - perp.x * amnt);
					targ[dnPos].set(dest.x - perp.y * amnt, dest.y + perp.x * amnt);

				} 
				
				amnt += pct; //this is what spreads the points out based on the brushWidth
				upPos++;
				dnPos--;
			}
						
			dontDraw = false;
		}
	
	
		
	
	
	protected:
		ofVec2f * pos;
		ofVec2f * targ;
		ofVec2f * vel;
		ofVec2f perp;
	
		float strokeSpeed;
		
		int total;
		int center;
		int hTotal; //half the total
		
		bool isSetup;
		bool dontDraw;
};


class vectorBrushRaster : public vectorBrush{


	public:
		
		
		//----------------------------
		void setupRasterImage(int w, int h){
			
			//check if we have setup the image already
			//why do I care?  donno really
			if(allocationCode == 1234599) return;
			
			width 	= w;
			height 	= h;
			
			totalPixels = width * height;
			pixels = new unsigned char[totalPixels];

			//hack alert! this so we know it has been setup
			//as we don't have access to the constructor
			//please kill me :) - "how not to program 101"
			allocationCode = 1234599;

			clear();
		}
		
		//----------------------------
		void clear(){
			if(allocationCode == 1234599)memset(pixels, 0, totalPixels);
		}
		
		//----------------------------
		~vectorBrushRaster(){
			if(allocationCode == 1234599){
				delete pixels;
			}
		}
		
		//----------------------------
		void drawIntoPixels(){
			if(dontDraw) return;
						
			for(int i = 0; i < total; i++){
				
				//north
				lineFast(targ[i].x  ,  targ[i].y+1,		pos[i].x,  pos[i].y+1,	255);
				//south
				lineFast(targ[i].x  ,  targ[i].y-1, 	pos[i].x,  pos[i].y-1,	255);
				
				//east
				lineFast(targ[i].x+1,  targ[i].y, 		pos[i].x-1,  pos[i].y,	255);
				//west
				lineFast(targ[i].x-1,  targ[i].y, 		pos[i].x-1,  pos[i].y,	255);
				
				//center :)
				lineFast(targ[i].x,  targ[i].y,  pos[i].x,  pos[i].y, 255);
			}
		}
		
		//----------------------------
		unsigned char * getPixels(){
			return pixels;
		}
		
		
		protected:
				
		//from http://www.cs.unc.edu/~mcmillan/comp136/Lecture6/Lines.html
		//----------------------------
		void lineFast(int x0, int y0, int x1, int y1, unsigned char value)
   		{
			int dy = y1 - y0;
			int dx = x1 - x0;
			int stepx, stepy;
			int pPos = 0;

			if (dy < 0) { dy = -dy;  stepy = -width; } else { stepy = width; }
			if (dx < 0) { dx = -dx;  stepx = -1; } else { stepx = 1; }
			dy <<= 1;
			dx <<= 1;

			y0 *= width;
			y1 *= width;
			
			pPos = x0+y0;
			if(pPos > 0 && pPos < totalPixels && x0 < width && x0 > 0) pixels[pPos] = value;
			
			if (dx > dy) {
			    int fraction = dy - (dx >> 1);
			    while (x0 != x1) {
			        if (fraction >= 0) {
			            y0 += stepy;
			            fraction -= dx;
			        }
			        x0 += stepx;
			        fraction += dy;
			        
			        pPos = x0+y0;
			        if(pPos > 0 && pPos < totalPixels && x0 < width && x0 > 0) pixels[pPos] = value;
			    }
			} else {
			    int fraction = dx - (dy >> 1);
			    while (y0 != y1) {
			        if (fraction >= 0) {
			            x0 += stepx;
			            fraction -= dy;
			        }
			        y0 += stepy;
			        fraction += dx;
			        
			        pPos = x0+y0;
			        if(pPos > 0 && pPos < totalPixels && x0 < width  && x0 > 0) pixels[pPos] = value;
			    }
			}
    	}
	
		int allocationCode; //biggest hack ever!!
		int totalPixels, width, height;
		unsigned char * pixels;
			
}; 



















#endif
