package other;

import network.Command;
import network.NetPack;
import network.Queue;

/**
 * Parser Klasse
 * Erstellt aus den eingegebenen Kommandos im Editorbereich
 * Command Objekte und legt diese in die Queue
 */
public class Parser {
	
	public static int ERROR_BRACE = 1;
	public static int ERROR_UNKNOWN_CMD = 2;
	
	Queue comQueue = null;
	int errorLine = 0 ;
	int errorCode = 0 ;
	
	/**
	 * Liefert das Ergebnis des Parsens
	 * @return eine Queue mit den Commands
	 */
	public Queue getQueue(){
		return comQueue;
	}
	
	/**
	 * Liefert die Zeile, in der der Fehler aufgetreten ist.
	 * @return Zeile in der ein Fehler aufgetreten ist
	 */
	public int getErrorLine(){
		return errorLine;
	}
	
	/**
	 * Liefert den Fehlercode, z.B. ERROR_UNKNOWN_CMD.
	 * @return den Errorcode der aufgetreten ist
	 */
	public int getErrorCode(){
		return errorCode;
	}
	
	/**
	 * Parst den übergebenen Text
	 * @param s auszuwertender String
	 * @return true, wenn Parsen erfolgreich
	 */
	public boolean parseString(String str){
		comQueue = new Queue();
		String arg, args[];
		Command cmd;
		
		errorLine=0;
		errorCode=0;
		
		// In Zeilen aufsplitten
		String[] lines = str.split("\n");

		// Jede Zeile einzeln durchgehen
		for(int i=0; i<lines.length;i++){
			// Whitespaces auslassen und alles zu Kleinbuchstaben
			lines[i]=lines[i].trim().toLowerCase();
			
			// Leere Zeilen und Kommentare auslassen
			if(lines[i].length()<=1) continue;
			if(lines[i].indexOf("//")==0) continue;
			
			args=null;
			
			try{
				// Argumente herausholen (zwischen Klammern)
				arg = lines[i].substring(lines[i].indexOf("(")+1,lines[i].indexOf(")"));
				
				// Argumente zwischen den Klammern auflösen
				if(arg.length()==0){
					args=null;
				}else{
					// Einzelne Argumente aufsplitten
					args = arg.split(",");
					
					// Konstantenauflösung
					for(int j=0;j<args.length;j++){
						args[j]=args[j].trim();
						if(args[j].equals("true")){ args[j]="1"; continue; }
						if(args[j].equals("false")){ args[j]="0"; continue; }
						if(args[j].equals("close")){ args[j]="1"; continue; }
						if(args[j].equals("open")){ args[j]="0"; continue; }
						if(args[j].equals("param_lin")){ args[j]=""+NetPack.PARAM_LIN; continue; }
						if(args[j].equals("param_direct")){ args[j]=""+NetPack.PARAM_DIRECT; continue; }
					}
				}
			}catch(Exception e){
				errorLine=i;
				errorCode=ERROR_BRACE;
				return false;
			}
			
			try{
				// Kommandos einzeln durchgehen
				if(lines[i].indexOf("moveposition")==0 && args[3].length()==2){
					//System.out.println("Hallo: " + args[3]);
					if(args[3].charAt(0)=='k')
						cmd = new Command(NetPack.MOVEPOS, 0, 0,
							Float.parseFloat(args[0]),
							Float.parseFloat(args[1]),
							Float.parseFloat(args[2]),
							args[3]);
					else
						cmd = new Command(NetPack.MOVEPOS, 0, 0,
								Float.parseFloat(args[0]),
								posToRad(Float.parseFloat(args[1])),
								Float.parseFloat(args[2]),
								args[3]);
					
				}else if(lines[i].indexOf("camif")==0){
					cmd = new Command(NetPack.CAMIF,
							Float.parseFloat(args[3]),
							Float.parseFloat(args[4]),
							Float.parseFloat(args[0]),
							Float.parseFloat(args[1]),(float)0,"ka");
					cmd.setiParam(Integer.parseInt(args[2]));
			
				}else if(lines[i].indexOf("camelse")==0){
					cmd = new Command(NetPack.CAMELSE);
					
				}else if(lines[i].indexOf("camendif")==0){
					cmd = new Command(NetPack.CAMENDIF);
					
				}else if(lines[i].indexOf("grip")==0){
						cmd = new Command(NetPack.GRIP,Integer.parseInt(args[0]),0);
						
				}else if(lines[i].indexOf("halt")==0){
					cmd = new Command(NetPack.HALT);
					
				}else if(lines[i].indexOf("offset")==0 && args[3].length()==2){
					cmd = new Command(NetPack.OFFSET, 0, 0,
							Float.parseFloat(args[0]),
							Float.parseFloat(args[1]),
							Float.parseFloat(args[2]),
							args[3]);
					
				}else if(lines[i].indexOf("motionspeed")==0){
					cmd = new Command(NetPack.MOTION_PERC,0,Float.parseFloat(args[0]));
					
				}else if(lines[i].indexOf("motionparam")==0){
					int a=0; // Alle Parameter zusammenzählen
					for(int j=0; j<args.length; j++) a+=Integer.parseInt(args[j]);
					cmd = new Command(NetPack.MOTION_PARAM,a,0);
					
				}else if(lines[i].indexOf("settransobj")==0){
					cmd = new Command(NetPack.SET_CUR_TRANSOBJ,Integer.parseInt(args[0]),0);
					
				}else if(lines[i].indexOf("loadbitmap")==0){
					cmd = new Command(NetPack.LOAD_BITMAP,Integer.parseInt(args[1]),args[0]);
					
				}else if(lines[i].indexOf("savebitmap")==0){
					cmd = new Command(NetPack.SAVE_BITMAP,0,args[0]);
					
				}else if(lines[i].indexOf("defineobstaclecircle")==0 && args[3].length()==2){
					cmd = new Command(NetPack.OBSTACLE_CIRCLE,
							Float.parseFloat(args[4]), 0,
							Float.parseFloat(args[0]),
							Float.parseFloat(args[1]),
							Float.parseFloat(args[2]),
							args[3]);
					
				}else if(lines[i].indexOf("defineobstaclerect")==0 && args[3].length()==2){
					cmd = new Command(NetPack.OBSTACLE_RECT,
							Float.parseFloat(args[4]),
							Float.parseFloat(args[5]),
							Float.parseFloat(args[0]),
							Float.parseFloat(args[1]),
							Float.parseFloat(args[2]),
							args[3]);
				}else if(lines[i].indexOf("movemodule")==0){
					int m = Integer.parseInt(args[0]);
					if(m==4)
						cmd = new Command(NetPack.MOVEMOD,
							m, posToRad(Float.parseFloat(args[1])));
					else
						cmd = new Command(NetPack.MOVEMOD,
								m, posToMeter(Float.parseFloat(args[1])));
							//System.out.prin
				}else if(lines[i].indexOf("movemodulestep")==0){
					cmd = new Command(NetPack.MOVEMODSTEP,
							Integer.parseInt(args[0]),
							Float.parseFloat(args[1]));
					
				}else if(lines[i].indexOf("waithome")==0){
					cmd = new Command(NetPack.WAITHOME);
					
				}else if(lines[i].indexOf("wait")==0){
					int w=0;
					// Paramter zusammenstöpseln
					for(int j=0; j<args.length; j++){
						if(args[j].equals("2"))
							w+=NetPack.WAIT_2;
						else if(args[j].equals("3"))
							w+=NetPack.WAIT_3;
						else if(args[j].equals("4"))
							w+=NetPack.WAIT_4;
						else
							throw new Exception();
					}
					if(w>7) throw new Exception();
					cmd = new Command(NetPack.WAIT, w, 0);
					
				}else if(lines[i].indexOf("home")==0){
					cmd = new Command(NetPack.HOME, Integer.parseInt(args[0]),0);

				}else if(lines[i].indexOf("reset")==0){
					cmd = new Command(NetPack.RESET, Integer.parseInt(args[0]),0);
					
				}else if(lines[i].indexOf("rampvel")==0){
					cmd = new Command(NetPack.RAMPVEL,
							Integer.parseInt(args[0]),
							Float.parseFloat(args[1]));
					
				}else if(lines[i].indexOf("rampacc")==0){
					cmd = new Command(NetPack.RAMPACC,
							Integer.parseInt(args[0]),
							Float.parseFloat(args[1]));
					
				}else if(lines[i].indexOf("sleep")==0){
					cmd = new Command(NetPack.SLEEP, Integer.parseInt(args[0]),0);
					
				}else if(lines[i].indexOf("savedatabase")==0){
					cmd = new Command(NetPack.SAVE_DATABASE);
					
				}else if(lines[i].indexOf("refreshdatabase")==0){
					cmd = new Command(NetPack.REFRESH_DATABASE);
					
				}else{
					throw new Exception();
				}
				
				// Command auf die Queue geben
				comQueue.enqueue(cmd);
				
			}catch(Exception e){
				errorLine=i;
				errorCode=ERROR_UNKNOWN_CMD;
				return false;
			}
		}
		return true;
	}

	/* ##########################################################################
	 * 						HILFSMETHODEN
	 * ##########################################################################*/		
	
	/**
	 * Umrechnung von Millimeter in Meter
	 * @param millimeter Wert der umgewandelt werden soll
	 * @return den Meterwert
	 */
	private float posToMeter(float millimeter){
		return millimeter/1000;
	}

	/**
	 * Umrechung von Grad in Radiant
	 * @param grad Wert der umgewandelt werden soll
	 * @return den Radwert
	 */
	private float posToRad(float grad){
		return grad*(float)Math.PI/180;
	}
	
}
