package com.krisharris.mpk;

import java.util.Vector;

import processing.core.PApplet;

/**
 * 
 * @author Kristopf
 */

public class Board {
	protected String type; // this can be either "Ethernet" or "USB"
	protected String location;
	protected String name;
	protected int serialnumber;
	protected Vector messageQueue;

	// 'Basic' Setup variables
	protected boolean cache_messages; // if true, all outgoing messages will
										// be sent back as incoming messages.
	// this could end up being very slow but is the best way I can think of to
	// do this, except making special Set*Out functions...think about speed and
	// infinate loops
	private boolean poll_analogin;
	private boolean poll_digitalin;
	private AnalogIn[] analogins;

	/**
	 * Typically called intenrally
	 * 
	 * @param _location
	 * @param _type
	 * @param _name
	 * @param _serialnumber
	 */
	public Board(String _location, String _type, String _name, int _serialnumber) {
		type = _type;
		location = _location;
		name = _name;
		serialnumber = _serialnumber;
		messageQueue = new Vector();
		poll_analogin = false;
		poll_digitalin = false;
		analogins = new AnalogIn[8];
		for (int i = 0; i < 8; i++) {
			analogins[i] = new AnalogIn();
		}
	}

	/**
	 * This function should only be called internally
	 * 
	 * 
	 * Structure of cacheing updates: message(s) received in
	 * MCProccessingConnect iff the message was sent by this board and
	 * cahce_messages==true send the message to this board (need a
	 * ODCMessageHandler - plus, i need a make a findBoardByAddress()) massive
	 * if..elseif to sort out all the possible messages - this should happen in
	 * Board to preserve OO probally parce the message out a bit (check format,
	 * i think it's /type/##/message) class at least for AnalogIn - need a
	 * private .set(value),public .calabrae( min,max) .value .calabrated
	 */
	protected void OSCMessage(OSCMessage m) {
		String message[] = PApplet.split(m.message, "/");
		// PApplet.println(message[1]);
		if (message[1].equals("system")) {
			if (message[2].equals("name")) {
				String s = (String) m.args.get(0);
				if (s != null) {
					name = s;
				}
			} else if (message[2].equals("serialnumber")) {
				Integer s = (Integer) m.args.get(0);
				if (s != null) {
					serialnumber = s.intValue();
				}
			}// /system/*
		} else if (message[1].equals("analogin")) {
			if (message[3].equals("value")) {
				// PApplet.println("/analogin/*/value");
				int which = PApplet.parseInt(message[2]);
				Integer v = (Integer) m.args.get(0);
				if (v != null)
					analogins[which].set(v.intValue());
				if (poll_analogin) {
					// sendMessage("/analogin/*/value",null);
				}
			}// /analogin/*/value
		}// /*
	}

	public String getType() {
		return type;
	}

	public String getLocation() {
		return location;
	}

	public String getName() {
		return name;
	}

	public int getSerialnumber() {
		return serialnumber;
	}

	/**
	 * 
	 * Sends a message by adding it to the queue. (Message will get sent after
	 * drawing)
	 *
	 * @param message the OSC message to send
	 * @param args (can be null) the paramaters of the message
	 */
	public void sendMessage(String message, Vector args) {
		OSCMessage msg = new OSCMessage(message);
		msg.address = location;
		msg.args = args;
		boolean match = false;
		for (int i = 0; i < messageQueue.size(); i++) { // check to see if there
														// is a matching message
			if (((OSCMessage) messageQueue.get(i)).message.equals(message)) {
				match = true;
			}
		}
		if (!match) // iff this message is not already being sent, send it
			messageQueue.add(msg);
	}

	/**
	 * Turn on or off the automatic polling of the analog inputs
	 * 
	 * @param p
	 *            set this to true to automatically poll analog inputs
	 */
	public void pollAnalogIn(boolean p) {
		poll_analogin = p;
	}
	/**
	 * retuns a {@link AnalogIn} reperesenting one of the 8 analog ins on the Making Things board
	 * @param which the analog in (0..7)
	 * @return The requested analog in, or null if it is out of range
	 */
	public AnalogIn analogIn(int which) {
		if (which < 0 || which > 7) {
			return null; // invalid
		} else {
			return analogins[which];
		}

	}
}
