package net.beadsproject.touch.examples;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.swing.JFrame;
import javax.swing.JPanel;

import net.beadsproject.beads.core.AudioContext;
import net.beadsproject.beads.core.UGen;
import net.beadsproject.beads.data.Pitch;
import net.beadsproject.beads.data.Sample;
import net.beadsproject.beads.data.SampleManager;
import net.beadsproject.beads.events.KillTrigger;
import net.beadsproject.beads.ugens.Envelope;
import net.beadsproject.beads.ugens.Gain;
import net.beadsproject.beads.ugens.PolyLimit;
import net.beadsproject.beads.ugens.SamplePlayer;
import net.beadsproject.beads.ugens.Static;
import net.beadsproject.beads.ugens.SamplePlayer.EnvelopeType;
import net.beadsproject.beads.ugens.SamplePlayer.InterpolationType;
import net.beadsproject.touch.hardware.PQLabsTouchSurface;
import net.beadsproject.touch.hardware.TouchSurface;
import net.beadsproject.touch.hardware.TouchSurfaceListener;
import net.beadsproject.touch.world.Region;
import net.beadsproject.touch.world.RegionMap;
import net.beadsproject.touch.world.World;
import processing.core.PGraphics;
import processing.core.PGraphics2D;
import processing.core.PImage;

/**
 * 
 * Fullscreen. Demonstrates using a JFrame instead of a PApplet.
 * 
 * @author ben
 *
 */
public class PianoPQInAJFrame extends JFrameFullScreenTouchSurface{
	
	public static class PianoRegion extends Region {
		public Sample s;
		public Point point;
		public Dimension size;
		
		public PianoRegion(Sample s, Point point, Dimension size)
		{
			this.s = s;
			this.point = point;
			this.size = size;
		}
	}
	
	public static class PianoPlayer
	{
		public PianoRegion region;
		public int x, y;
		
		public void setPosition(int x, int y)
		{
			this.x = x;
			this.y = y;
		}
		
		public void setRegion(PianoRegion pr)
		{
			region = pr;
			if (pr==null) return;
			SamplePlayer sp = new SamplePlayer(PianoWorld.ac,pr.s);
			sp.setEnvelopeType(EnvelopeType.COARSE);
			sp.setInterpolationType(InterpolationType.NONE);
			sp.setKillOnEnd(true);
			
			Envelope env = new Envelope(PianoWorld.ac, 1f);
			Gain g = new Gain(PianoWorld.ac, 2, env);
			g.addInput(sp);
			env.addSegment(0f, 1000f, new KillTrigger(g));
			
			PianoWorld.g.addInput(g);
		}
	}
	
	public static class PianoWorld extends World implements TouchSurfaceListener
	{
		public static UGen g;
		public static AudioContext ac;
		
		public int width, height;
		
		public RegionMap regionMap;		
		public PImage displayImage;
		
		private HashMap<Integer,PianoPlayer> players;
		
		public PianoWorld(PGraphics img, final AudioContext ac, int w, int h)
		{
			PianoWorld.ac = ac;
			width = w;
			height = h;
			players = new HashMap<Integer,PianoPlayer>();
			
			//set up connection point
			PolyLimit p = new PolyLimit(ac, 2, 12);
			Gain g = new Gain(ac,2,new Static(ac,4.0f));
			ac.out.addInput(g);
			g.addInput(p);
			PianoWorld.g = p;
							
			String noteDir = "audio/piano";
			Sample[] sampleList = new Sample[12];
			//add notes, one octave at mid register
			SampleManager.setBufferingRegime(Sample.Regime.newTotalRegime());
			for(int i = 0; i < 12; i++) {				
				sampleList[i] = SampleManager.sample(noteDir + "/" + "Piano.mf." + Pitch.pitchNames[i] + "5" + ".wav");
			}
			SampleManager.group("piano", sampleList);
			
			// Generate regions and visual representation
			PianoRegion[] regions = new PianoRegion[12];
			HashMap<Region,Color> regionColours = new HashMap<Region,Color>();
			
			regionMap = new RegionMap(width,height);			
			img.beginDraw();
			img.background(0);
			img.noStroke();
			
			float dw = width/12.f;
			for(int i=0; i<12; i++)
			{
				// we divide the space vertically
				regions[i] = new PianoRegion(sampleList[i],new Point((int) (i*dw),0),new Dimension((int) dw,height));
				regionColours.put(regions[i], new Color(Color.HSBtoRGB((float) Math.random(), .75f, .75f)));
				
				RegionMap.PSetFill(img, i);
				img.rect(i*dw,0,dw,height);
			}			
			img.endDraw();
			
			regionMap.generateFromPGraphics(img, regions);			
			displayImage = regionMap.generatePImage(img, regionColours);			
		}		
		
		public void paint(Graphics g)
		{
			g.drawImage(displayImage.getImage(), 0, 0, null);			
			Color keyHighlight = new Color(1f,1f,1f,.55f);
			Color playerColor = Color.black;
			Set<Region> drawn = new HashSet<Region>();
			
			for(PianoPlayer pp: players.values())
			{
				if (!drawn.contains(pp.region))
				{				
					Point pt = pp.region.point;
					Dimension d = pp.region.size;
					
					g.setColor(keyHighlight);
					g.fillRect(pt.x, pt.y, d.width, d.height);
					
					drawn.add(pp.region);
				}
			}
			for (PianoPlayer pp: players.values())
			{
				g.setColor(playerColor);
				g.drawOval(pp.x, pp.y, 20, 20);
			}			
		}

		@Override
		public List<Region> getRegions() {
			// TODO Auto-generated method stub
			return null;
		}
		
		@Override
		public void contactEnded(int ID) {
			// TODO Auto-generated method stub
			players.remove(ID);
		}

		@Override
		public void contactMoved(int ID, Region dest) {
			PianoPlayer pp = players.get(ID);
			if (pp!=null)
			{
				pp.setRegion((PianoRegion)(dest));
			}			
		}
		
		public void contactMoved(int ID, int x, int y) {
			PianoPlayer pp = players.get(ID);
			Region r = regionMap.get(x,y);
			pp.setPosition(x,y);
			if (pp!=null && r!=null && r!=pp.region)
			{
				pp.setRegion((PianoRegion)(r));
			}			
		}

		@Override
		public void newContact(int ID, Region region) {
			// generate a new guy and play a sound
			PianoPlayer pp = new PianoPlayer();
			pp.setRegion((PianoRegion)(region));	
			players.put(ID,pp);
		}		
		
		public void newContact(int ID, int x, int y) {
			// generate a new guy and play a sound
			Region r = regionMap.get(x,y);			
			if (r!=null)
			{
				PianoPlayer pp = new PianoPlayer();
				pp.setRegion((PianoRegion)(r));
				pp.setPosition(x,y);
				players.put(ID,pp);
			}
		}

		@Override
		public void moved(int id, int x, int y) {
			contactMoved(id,x,y);
		}

		@Override
		public void pressed(int id, int x, int y) {
			newContact(id,x,y);		
		}

		@Override
		public void released(int id) {
			contactEnded(id);			
		}
	}
	
	PianoWorld world;	
	PGraphics gfx;
		
	public PianoPQInAJFrame()
	{
		gfx = new PGraphics2D();
        gfx.setPrimary(false);
        gfx.setSize(frame.getWidth(), frame.getHeight());
		
        AudioContext ac = new AudioContext();
        world = new PianoWorld(gfx, ac, frame.getWidth(), frame.getHeight());	
        touchSurface = new PQLabsTouchSurface();
		touchSurface.setListener(world);
		touchSurface.start();		
		ac.start();					
	}
	
	public void paint(Graphics g)
	{
		g.clearRect(0,0,width,height);
		world.paint(g);
	}
	
	public static void main(String[] args)
	{
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
		    public void run() 
		    {
		    	new PianoPQInAJFrame();
		    }
	    });
	}
}
