Module("turtle", "0.0.1",function(thisMod){
    
    thisMod.CmdError=Class("CmdError", Exception, function(thisClass, Super){
        thisClass.prototype.init = function(cmd, trace){
            Super.prototype.init.call(this, thisMod, "Error trying to execute command: " + cmd , trace);
        }
    })
    thisMod.ScriptError=Class("ScriptError", Exception, function(thisClass, Super){
        thisClass.prototype.init = function(script, line, trace){
            Super.prototype.init.call(this, thisMod, "Error executing script: " + script + " at line: " + line , trace);
        }
    })
    
    thisMod.Turtle=Class("Turtle", function(thisClass, Super){
        thisClass.prototype.init = function(path, marker, trace, help){
            this.path=path;
            this.turtle=marker;
            this.helpFn = help;
            this.trace = trace;
            
            this.cmdList = new Array();
            this.scripts = {};
            
            this.cmdTable = { lowerthepen : "lowerThePen",
                                      lo : "lowerThePen",
                                      liftthepen : "liftThePen",
                                      li : "liftThePen",
                                      forward : "forward",
                                      fo : "forward",
                                      turn : "turn",
                                      tu : "turn",
                                      startnew : "startNew",
                                      st : "startNew",
                                      save : "save",
                                      sa : "save",
                                      help: "help",
                                      trace : "trace",
                                      senkestift : "senkeStift",
                                      se : "senkeStift",
                                      hebestift : "hebeStift",
                                      he : "hebeStift",
                                      vor : "vor",
                                      vo : "vor",
                                      drehe : "drehe",
                                      dr : "drehe",
                                      neueranfang : "neuerAnfang",
                                      ne : "neuerAnfang",
                                      speicher : "speicher",
                                      sp : "speicher",
                                      hilfe : "hilfe"
                                    }
                                    
            this.startNew();
        }
        
        thisClass.prototype.forward=function(steps){
            steps = parseInt(steps);
            if (isNaN(steps)){
                throw "steps"
            }
            
            var curra = Number(this.turtle.getAttribute("orient"));
            var newx=Math.sin((180-curra) * Math.PI/180)*steps;
            var newy=Math.cos((180-curra)* Math.PI/180)*steps;
            if(this.isPenDown())
                newx =" l" + newx;
            else
                newx =" m" + newx;
            this.path.setAttribute("d" , this.path.getAttribute("d") + newx + "," + newy) 
            return "forward " + steps;
        }
        
        thisClass.prototype.turn=function(angle){
            angle = parseInt(angle);
            
            if (isNaN(angle)){
                throw "angle"
            }
            var curra = Number(this.turtle.getAttribute("orient"));
            this.turtle.setAttribute("orient", (curra + angle) % 360);
            return "turn " + angle;
        }
        
        thisClass.prototype.lowerThePen=function(){
            this.turtle.setAttribute("fill","blue");
            return "lowerThePen";
        }
        
        thisClass.prototype.liftThePen=function(){
            this.turtle.setAttribute("fill","none");
            return "liftThePen";
        }
        
        thisClass.prototype.startNew=function(){
            this.turtle.setAttribute("orient", 0);
            this.turtle.setAttribute("fill","none");
            this.path.setAttribute("d", "M500,500");
            this.cmdList = [];
        }
        
        thisClass.prototype.save=function(name){
            if (name.replace(" ", "") == ""){
                throw "name";
            }
            this.scripts[name] = this.cmdList.join("\n");
            this.startNew();
        }
        thisClass.prototype.help=function(){
            this.helpFn("en");
        }
        
        thisClass.prototype.senkeStift=function(){
            this.lowerThePen();
            return "senkeStift";
        }
        thisClass.prototype.hebeStift=function(){
            this.liftThePen();
            return "hebeStift";
        }
        thisClass.prototype.vor=function(steps){
            this.forward(steps);
            return "vor " + steps;
        }
        
        thisClass.prototype.drehe=function(deg){
            this.turn(deg);
            return "drehe " + deg;
        }
        thisClass.prototype.neuerAnfang=function(){
            this.startNew();
        }
        thisClass.prototype.speicher=function(name){
            this.save(name);
        }
        thisClass.prototype.hilfe=function(){
            this.helpFn("de")
        }
        
        
        thisClass.prototype.isPenDown=function(){
            return (this.turtle.getAttribute("fill") == "blue");
        }
        
        
        thisClass.prototype.execCommand2 =function(cmd){
            if(cmd.replace(" ", "") != ""){
                var cmds = cmd.toLowerCase().match(/(\w+)\s*(\w+|$)/);    
                var cmdName = cmds[1];
                var param = cmds[2];
                
                try{
                    var methName = this.cmdTable[cmdName];
                }catch(e){
                    var methName = null;                
                }
                
                if(methName){
                    return this[methName](param);    
                }else{
                    try{
                        this.runScript(cmdName);
                        return cmdName;
                    }catch(e){                
                        throw new thisMod.CmdError(cmdName);
                    }
                }
            }
        }
        
        thisClass.prototype.execCommand=function(cmd){
            try{
                var cmd = this.execCommand2(cmd);
                if(cmd){
                    this.cmdList.push(cmd);
                }
            }catch(e){
                showError(cmd + " ?");
            }
        }
        
        thisClass.prototype.runScript=function(scriptName){
            
            try{
                var scr = this.scripts[scriptName];
            }catch(e){
                throw new thisMod.ScriptError(scriptName, 0, "script not found: " + scriptName);
            }
            
            if(scr){
                var cmds = scr.split("\n");
                for(var i=0;i<cmds.length;i++){
                    try{
                        this.execCommand2(cmds[i])
                    }catch(e){
                        throw new thisMod.ScriptError(scriptName, i + 1, e);
                    }
                }
                return scriptName;
            }else{
                throw new thisMod.ScriptError(scriptName, 0, "script not found: " + scriptName);
            }
        }
    })
})



