package Cluedo.API;

import java.awt.Point;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;


/**
 * Load map area nodes from XML data file.
 * 
 * @author Alex Ellis
 */
public class MapLoader {
	ArrayList definedNodes = new ArrayList();

	int debug = 0;
	
	DefaultHandler defaultLoadHandler = new DefaultHandler() {
		String lastSection = "";
		
		MapArea currentNode = null;
		Point currentPoint = null;
		
		ArrayList playerPoints = new ArrayList();
		
		ArrayList areaPoints = new ArrayList();
		

		boolean inNodes = false;
		boolean inNode = false;
		boolean inNodeName = false;

		boolean inPositions = false;
		boolean inPoints = false;
		
		boolean inNodePoint = false;

		boolean inPointX = false;
		boolean inPointY = false;
		
		String nodeName = "";
		
			
		public void characters(char [] buf, int offset, int len) {	
			String s = new String(buf, offset, len);
			s = s.trim();
			if(s.equals(""))
				return;
			
/*			if(inNodeName == true)
				System.out.println("Feedback '"+s);*/
			
			if(inNode == true) {
				if(inNodeName == true) {
					// TODO: Very dirty nasty hack to get over the name bug
					nodeName += s;
				}
				else if(inNodePoint == true) {
					if(inPointX) {
						currentPoint = new Point();
						currentPoint.x = Integer.parseInt(s);
					}
					else if(inPointY) {
						currentPoint.y = Integer.parseInt(s);
						//System.out.println(currentPoint.toString());
					}
					
				}

			}			
			
		}

		public void endElement(String namespaceURI, String localName, String qName) {

			//System.out.println("End: [" + qName+"]");
			if(qName.equals("nodes")) {
				inNodes = false;
			}
			else if(qName.equals("node")) {
				inNode = false;
				//System.out.println("Ending points for " + nodeName + " no: " + areaPoints.size() +" / "+ playerPoints.size());
				/*
				Define current node somehow add all points to it
				
				*/
			
				float[][] nodesData = new float[areaPoints.size()][2];
				Point point = null;
				for(int i = 0; i < areaPoints.size(); i++) {
					point = (Point)areaPoints.get(i);
					nodesData[i][0]	= point.x;
					nodesData[i][1]	= point.y;
				}

				currentNode = new MapArea(nodeName, nodesData);
				currentNode.setPiecePoints(playerPoints);
				
				definedNodes.add(currentNode);
				
			}
			else if(qName.equals("ID")) {
				inNodeName = false;
			}
			else if(qName.equals("points")) {
				inPoints = false;

			}
			else if(qName.equals("positions")) {
				inPositions = false;

			}
			else if(qName.equals("point")) {
				inNodePoint = false;
				
				if(inPositions) {
					playerPoints.add( currentPoint );
				}
				else {
					areaPoints.add( currentPoint );
				}

			}
			
			if(inNodePoint == true) {
				if(qName.equals("x")) {
					inPointX = false;
                        	
				}
				else if(qName.equals("y")) {
					inPointY = false;

                        	
				}
			}
		}


		public void startElement(String namespaceURI, String localName, String qName, Attributes atts) {

			lastSection = qName;
			
			if(qName.equals("nodes")) {
				inNodes = true;	
			}
			else if(qName.equals("node")) {
				inNode = true;
				areaPoints = new ArrayList();
				playerPoints = new ArrayList();
				// in theory currentNode = new MapArea();
			}
			else if(qName.equals("ID")) {
				inNodeName = true;
				nodeName = "";

			}
			else if(qName.equals("points")) {
				inPoints = true;

			}
			else if(qName.equals("positions")) {
				inPositions = true;

			}
			else if(qName.equals("point")) {
				inNodePoint = true;
				currentPoint = new Point();
			}
			
			if(inNodePoint == true) {
				if(qName.equals("x")) {
					inPointX = true;
                        	
				}
				else if(qName.equals("y")) {
					inPointY = true;
                        	
				}
			}

	
		}

	};
	
	public MapLoader() {
		
	}


	/**
	 * For debugging purposes only
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		String fileName = "../../Maps/default.xml";
		
		MapLoader ml = new MapLoader();
		
		URL fileUrl = ml.getClass().getResource(fileName);
		
		if(fileUrl == null) {
			System.out.println("Unable to find file.");
			System.exit(-1);
		}		
		File file = new File(fileUrl.getFile());

		fileName = file.getPath();
		System.out.println(fileName);
		
		try { 
			ml.loadGame(fileName);
		}
		catch(IOException error) {
			System.out.println("[GamePersitance:loadGame] Unable to load file.");
		}
		catch (Exception error) {
			System.out.println("[GamePersitance:loadGame] Other error.");
		}

	}
	

	public ArrayList getMapAreas() {
		return definedNodes;
	}

	public void loadGame(String fileName) throws ParserConfigurationException, SAXException, IOException, NullPointerException  {

		SAXParserFactory factory = SAXParserFactory.newInstance();
		SAXParser saxParser = factory.newSAXParser();
		saxParser.parse( fileName, defaultLoadHandler );

		System.out.println("mapAreas found: "+definedNodes.size());
	}

}
