import net.beadsproject.beads.core.AudioContext;
import net.beadsproject.beads.data.Sample;
import net.beadsproject.beads.ugens.SamplePlayer;
import processing.core.PApplet;
import processing.core.PGraphics;

/**
 * A gui control that provides a simple 2d array of buttons.
 * 
 * @author ben
 */
public class GridControl {
	static final int SIZEW = 32;
	static final int GRIDW = 8;
	static final int PPG = 8; // pixels per grid
	static final public int MSWIDTH = 4000; // 3 seconds wide
	static final public int WIDTH = SIZEW*PPG;
	
	public int SIZEH;
	public int HEIGHT;	
	
	private boolean[][] array;
	
	int x, y;
	PGraphics pg;
	SamplePlayer sp[];
	SoundEffect se;
	AudioContext ac;
	boolean isMuted;
	int currentFrame;
	float tx;
	
	public GridControl(AudioContext ac, PApplet papplet, int x, int y, SoundEffect se)
	{
		this(ac,papplet,4,x,y,se);
	}
	
	public GridControl(AudioContext ac, PApplet papplet, int numrows, int x, int y, SoundEffect se)
	{
		SIZEH = numrows;
		HEIGHT = SIZEH*PPG;
		
		currentFrame = 0;
		isMuted = false;
		this.ac = ac;
		this.x = x;
		this.y = y;
		this.se = se;
		this.pg = papplet.createGraphics(WIDTH,HEIGHT,papplet.JAVA2D);
		array = new boolean[SIZEW][];
		for(int i=0;i<SIZEW;i++) array[i] = new boolean[SIZEH];
		for(int i=0;i<SIZEW;i++)
			for(int j=0;j<SIZEH;j++)
				set(i,j,false);				
	}
	
	public void setup()
	{
		// for each row, we make a copy of the soundeffect, pitch shifting up by some amount
		sp = new SamplePlayer[SIZEH];
		for(int j=0;j<SIZEH;j++)
		{			
			Sample s = setupSoundEffect(j,se).toSample(ac);
			sp[j] = new SamplePlayer(ac,s);
			sp[j].setLoopType(SamplePlayer.LoopType.NO_LOOP_FORWARDS);
			sp[j].setKillOnEnd(false);
			sp[j].pause(true);
			ac.out.addInput(sp[j]);
		}
	}
	
	public SoundEffect setupSoundEffect(int j, SoundEffect se)
	{
		SoundEffect se2 = new SoundEffect(se);
		se2.Frequency*=(1 + j);
		se2.MinFrequency*=(1+j);	
		return se2;
	}
	
	public void setTime(float ms)
	{
		float dt = ms / MSWIDTH;
		tx = dt*WIDTH;
		if (!isMuted)
		{
			int frame = (int)(dt*SIZEW);
			if (frame!=currentFrame)
				activateFrame(frame);
		}
	}
	
	public void activateFrame(int f)
	{
		currentFrame = f % SIZEW;
		
		for(int j=0;j<SIZEH;j++)
			if (get(f,j)) sp[j].reTrigger();
	}
	
	public boolean get(int i, int j)
	{
		return array[i][j];
	}
	
	public void set(int i, int j, boolean b)
	{
		array[i][j] = b;
	}
	
	public void clear()
	{
		for(int i=0;i<SIZEW;i++)
			for(int j=0;j<SIZEH;j++)
				array[i][j] = false;
	}
	
	public void random()
	{
		for(int i=0;i<SIZEW;i++)
			for(int j=0;j<SIZEH;j++)
				array[i][j] = Math.random()>0.8;
	}
	
	public void mute()
	{
		isMuted = true;
	}
	
	public boolean muted()
	{
		return isMuted;
	}
	
	public void unmute()
	{
		isMuted = false;
	}
	
	public void mousePressed(int mx, int my)
	{
		if (inBounds(mx,my))
		{
			int i = (mx - 1 - x)/PPG;
			int j = (my - 1 - y)/PPG;
			set(i,j,!get(i,j));
		}
	}
	//////////////////////////////////
	//OLLIE
	private int lastX = -1, lastY = -1;
	public void mouseReleased(int mx, int my)
	{
		lastX = -1;
		lastY = -1;
	}
	
	public void mouseDragged(int mx, int my)
	{
		if (inBounds(mx,my))
		{
			int i = (mx - 1 - x)/PPG;
			int j = (my - 1 - y)/PPG;
			if(i != lastX || j != lastY) {
				set(i,j,!get(i,j));
				lastX = i;
				lastY = j;
			}
		}
	}
	///////////////////////////////////////////
	
	public boolean inBounds(int mx, int my)
	{
		if (mx<x || my<y || mx>(x+WIDTH) || my>(y+HEIGHT)) return false;
		else return true;
	}
	
	public void draw()
	{
		pg.beginDraw();
		if (isMuted)
			pg.fill(100);
		else
			pg.fill(0);
		pg.stroke(0,0,255);
		pg.strokeWeight(1);
		pg.rect(0,0,WIDTH,HEIGHT);
		pg.noFill();
		
		pg.stroke(80,80,80);
		for(int i=0;i<SIZEW/GRIDW;i++)
			pg.line(PPG*i*GRIDW,0,PPG*i*GRIDW,HEIGHT);
		
		pg.strokeWeight(2);
		pg.line(tx,0,tx,HEIGHT);
		
		pg.noStroke();
		pg.fill(0,0,255);
		for(int i=0;i<SIZEW;i++)
		for(int j=0;j<SIZEH;j++)
		{
			if (get(i,j)) 
			{
				// float dtx = Math.abs(i - tx)/WIDTH;
				if (Math.abs(i*PPG-tx) < PPG) pg.fill(255,255,255);
				else pg.fill(0,0,255);
				pg.rect(i*PPG,j*PPG,PPG,PPG);
			}
		}
		
		
		pg.endDraw();
	}
	
}
