var jsonParse = (function () {
  var number
      = '(?:-?\\b(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b)';
  var oneChar = '(?:[^\\0-\\x08\\x0a-\\x1f\"\\\\]'
      + '|\\\\(?:[\"/\\\\bfnrt]|u[0-9A-Fa-f]{4}))';
  var string = '(?:\"' + oneChar + '*\")';

  // Will match a value in a well-formed JSON file.
  // If the input is not well-formed, may match strangely, but not in an unsafe
  // way.
  // Since this only matches value tokens, it does not match whitespace, colons,
  // or commas.
  var jsonToken = new RegExp(
      '(?:false|true|null|[\\{\\}\\[\\]]'
      + '|' + number
      + '|' + string
      + ')', 'g');

  // Matches escape sequences in a string literal
  var escapeSequence = new RegExp('\\\\(?:([^u])|u(.{4}))', 'g');

  // Decodes escape sequences in object literals
  var escapes = {
    '"': '"',
    '/': '/',
    '\\': '\\',
    'b': '\b',
    'f': '\f',
    'n': '\n',
    'r': '\r',
    't': '\t'
  };
  function unescapeOne(_, ch, hex) {
    return ch ? escapes[ch] : String.fromCharCode(parseInt(hex, 16));
  }

  // A non-falsy value that coerces to the empty string when used as a key.
  var EMPTY_STRING = new String('');
  var SLASH = '\\';

  // Constructor to use based on an open token.
  var firstTokenCtors = { '{': Object, '[': Array };

  var hop = Object.hasOwnProperty;

  return function (json, opt_reviver) {
    // Split into tokens
    var toks = json.match(jsonToken);
    // Construct the object to return
    var result;
    var tok = toks[0];
    var topLevelPrimitive = false;
    if ('{' === tok) {
      result = {};
    } else if ('[' === tok) {
      result = [];
    } else {
      // The RFC only allows arrays or objects at the top level, but the JSON.parse
      // defined by the EcmaScript 5 draft does allow strings, booleans, numbers, and null
      // at the top level.
      result = [];
      topLevelPrimitive = true;
    }

    // If undefined, the key in an object key/value record to use for the next
    // value parsed.
    var key;
    // Loop over remaining tokens maintaining a stack of uncompleted objects and
    // arrays.
    var stack = [result];
    for (var i = 1 - topLevelPrimitive, n = toks.length; i < n; ++i) {
      tok = toks[i];

      var cont;
      switch (tok.charCodeAt(0)) {
        default:  // sign or digit
          cont = stack[0];
          cont[key || cont.length] = +(tok);
          key = void 0;
          break;
        case 0x22:  // '"'
          tok = tok.substring(1, tok.length - 1);
          if (tok.indexOf(SLASH) !== -1) {
            tok = tok.replace(escapeSequence, unescapeOne);
          }
          cont = stack[0];
          if (!key) {
            if (cont instanceof Array) {
              key = cont.length;
            } else {
              key = tok || EMPTY_STRING;  // Use as key for next value seen.
              break;
            }
          }
          cont[key] = tok;
          key = void 0;
          break;
        case 0x5b:  // '['
          cont = stack[0];
          stack.unshift(cont[key || cont.length] = []);
          key = void 0;
          break;
        case 0x5d:  // ']'
          stack.shift();
          break;
        case 0x66:  // 'f'
          cont = stack[0];
          cont[key || cont.length] = false;
          key = void 0;
          break;
        case 0x6e:  // 'n'
          cont = stack[0];
          cont[key || cont.length] = null;
          key = void 0;
          break;
        case 0x74:  // 't'
          cont = stack[0];
          cont[key || cont.length] = true;
          key = void 0;
          break;
        case 0x7b:  // '{'
          cont = stack[0];
          stack.unshift(cont[key || cont.length] = {});
          key = void 0;
          break;
        case 0x7d:  // '}'
          stack.shift();
          break;
      }
    }
    // Fail if we've got an uncompleted object.
    if (topLevelPrimitive) {
      if (stack.length !== 1) { throw new Error(); }
      result = result[0];
    } else {
      if (stack.length) { throw new Error(); }
    }

    if (opt_reviver) {
      // Based on walk as implemented in http://www.json.org/json2.js
      var walk = function (holder, key) {
        var value = holder[key];
        if (value && typeof value === 'object') {
          var toDelete = null;
          for (var k in value) {
            if (hop.call(value, k) && value !== holder) {
              // Recurse to properties first.  This has the effect of causing
              // the reviver to be called on the object graph depth-first.

              // Since 'this' is bound to the holder of the property, the
              // reviver can access sibling properties of k including ones
              // that have not yet been revived.

              // The value returned by the reviver is used in place of the
              // current value of property k.
              // If it returns undefined then the property is deleted.
              var v = walk(value, k);
              if (v !== void 0) {
                value[k] = v;
              } else {
                // Deleting properties inside the loop has vaguely defined
                // semantics in ES3 and ES3.1.
                if (!toDelete) { toDelete = []; }
                toDelete.push(k);
              }
            }
          }
          if (toDelete) {
            for (var i = toDelete.length; --i >= 0;) {
              delete value[toDelete[i]];
            }
          }
        }
        return opt_reviver.call(holder, key, value);
      };
      result = walk({ '': result }, '');
    }

    return result;
  };
})();

// -----------------------------------------------------------------
function capFirst(str)
{
    return str.charAt(0).toUpperCase() + str.slice(1);
}


	function gup( name ) {
	name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
	var regexS = "[\\?&]"+name+"=([^&#]*)";
	var regex = new RegExp( regexS );
	var results = regex.exec( window.location.href );
 	if( results == null )
		return "";
	else
    	return results[1];
}

function goBack() {
	if (window.myStatus[0] > 0 && window.myStatus[1] > 0) {
		textGrey();
		window.myStatus[0] = window.myStatus[0] -1;
		speech("<p>" + window.lesson[window.myStatus[0]][1] + "</p>");
	}
}

function addValue() {
    window.myStatus[0] = window.myStatus[0] +1;
}

function clearValue() {
    window.myStatus[0] = 0;
}

function checkAnswer(test, num) {
test = capFirst(test.replace(/[,\!\.\?\*]/ig,""));
	if (window.lesson[num][0] == 0) {
		for (i=2;i<window.lesson[num].length;i++) {
			check = capFirst(window.lesson[num][i].replace(/[,\!\.\?\*]/ig,""));
			if (test == check) {
					window.myStatus[2]++;
					return true;
				}
		} 
	} else if (window.lesson[num].length > 4) {
		for (i=4;i<window.lesson[num].length;i++) {
				check = capFirst(window.lesson[num][i].replace(/[,\!\.\?\*]/ig,""));
			if (test == check) {
					window.myStatus[2]++;
					return true;
				}
		}
	}
return false;
}

function textRed() {
	document.getElementById("txt1").style.borderColor="red";
}

function textGrey() {
	document.getElementById("txt1").style.borderColor="#cccccc";
}

function textGreen() {
	document.getElementById("txt1").style.borderColor="green";
}

function makeBlank(temp)
{
temp = temp || window.event;
var elem = temp.srcElement || temp.target;
elem.value = "";
}

function enter_pressed(e) {
	var keycode;
	if (window.event) {
		keycode = window.event.keyCode;
	}
	else if (e) {
		keycode = e.which;
	}
	else return false;
	return (keycode == 13);
}

function swapGerman(str) {
    str = str.replace("ä","ae"); 
    str = str.replace("ö","oe");
    str = str.replace("ü","ue");
    str = str.replace("ß","ss");
    return str;
    }
    
var FlashHelper =
{
	movieIsLoaded : function (theMovie)
	{
		if (typeof(theMovie) != "undefined") return theMovie.PercentLoaded() == 100;
		else return
		false;
  },

	getMovie : function (movieName)
	{
  	if (navigator.appName.indexOf ("Microsoft") !=-1) return window[movieName];
	  else return document[movieName];
	}
};

function niftyplayer(name)
{
	this.obj = FlashHelper.getMovie(name);

	if (!FlashHelper.movieIsLoaded(this.obj)) return;

	this.play = function () {
		this.obj.TCallLabel('/','play');
	};

	this.stop = function () {
		this.obj.TCallLabel('/','stop');
	};

	this.pause = function () {
		this.obj.TCallLabel('/','pause');
	};

	this.playToggle = function () {
		this.obj.TCallLabel('/','playToggle');
	};

	this.reset = function () {
		this.obj.TCallLabel('/','reset');
	};

	this.load = function (url) {
		this.obj.SetVariable('currentSong', url);
		this.obj.TCallLabel('/','load');
	};

	this.loadAndPlay = function (url) {
		this.load(url);
		this.play();
	};

	this.getState = function () {
		var ps = this.obj.GetVariable('playingState');
		var ls = this.obj.GetVariable('loadingState');

		// returns
		//   'empty' if no file is loaded
		//   'loading' if file is loading
		//   'playing' if user has pressed play AND file has loaded
		//   'stopped' if not empty and file is stopped
		//   'paused' if file is paused
		//   'finished' if file has finished playing
		//   'error' if an error occurred
		if (ps == 'playing')
			if (ls == 'loaded') return ps;
			else return ls;

		if (ps == 'stopped')
			if (ls == 'empty') return ls;
			if (ls == 'error') return ls;
			else return ps;

		return ps;

	};

	this.getPlayingState = function () {
		// returns 'playing', 'paused', 'stopped' or 'finished'
		return this.obj.GetVariable('playingState');
	};

	this.getLoadingState = function () {
		// returns 'empty', 'loading', 'loaded' or 'error'
		return this.obj.GetVariable('loadingState');
	};

	this.registerEvent = function (eventName, action) {
		// eventName is a string with one of the following values: onPlay, onStop, onPause, onError, onSongOver, onBufferingComplete, onBufferingStarted
		// action is a string with the javascript code to run.
		//
		// example: niftyplayer('niftyPlayer1').registerEvent('onPlay', 'alert("playing!")');

		this.obj.SetVariable(eventName, action);
	};

	return this;
}    
    
function addSound(str) {
	temp = str.split("*");
	var mid = [];
	if (temp.length == 3) {
		words = temp[1].split(" ");
		for (var i = 0; i < words.length; i++) {
			clean = swapGerman(words[i].toLowerCase())
			clean = clean.replace(/[,\!\.\?]/ig,"");
			str = "<a href=\"javascript:niftyplayer('niftyPlayer1').loadAndPlay('audio/" + clean + ".mp3');\">" + words[i] +"</a>";	
			mid.push(str);	
		}
		temp[1] = mid.join(" ");
		str = temp.join("");
		}			
return str;
}


function speech(str) {
	xmlhttp=GetXmlHttpObject();
	if (xmlhttp==null) {
		alert ("Your browser does not support XMLHTTP!");
		return;
	}
	str=addSound(str);
	document.getElementById("txtHint").innerHTML=str;
}

function pickOutput(num, plus) {
if (window.lesson[window.myStatus[0]][0] == 0) {
speech("<p><em>" + window.lesson[window.myStatus[0]][2] + "</em></p> " + 
		"<p>" + window.lesson[window.myStatus[0]+plus][1] + "</p>");
} else if (!window.lesson[window.myStatus[0]][num] == "") {
		speech("<p>" + window.lesson[window.myStatus[0]][num] + " " + 
			window.lesson[window.myStatus[0]+plus][1] + "</p>");
	} else 
		speech("<p>" + window.lesson[window.myStatus[0]+plus][1] + "</p>");
}

function correctionOutput(answer, entry) {  // function   
	var punct = answer.split(" ");
	for (var i = 0; i < punct.length; i++) { // first for
	punct[i] = punct[i].replace(/[^,\!\.\?]/ig,"");
	} // first for
	e = swapGerman(entry).replace(/[,\!\.\?\*]/ig,"").split(" ");  
    a = answer.replace(/[,\!\.\?\*]/ig,"").split(" ");
    a2 = swapGerman(answer).replace(/[,\!\.\?\*]/ig,"").split(" ");
    //e = entry.replace(/[,\!\.\?\*]/ig,"").split(" ");    
	w = [];
	e2 = [];
	for (var i = 0; i < a.length; i++) { // second for
		if (a2[i] == e[i]) 
			w[i] = a[i] + punct[i];
		else { // else
			w[i] = "<span class=\"red\">" + a[i] + "<\/span>" +punct[i];
		} // else
	} // second for
	return w.join(" ");
} // function


function stateChanged() {
	if (xmlhttp.readyState==4) {
		var myJsonObj = jsonParse(xmlhttp.responseText);
		window.lesson = myJsonObj;
		speech("<p>" + window.lesson[0][1] + "</p>");
  	}
}

function GetXmlHttpObject() {
	if (window.XMLHttpRequest)	{
	// code for IE7+, Firefox, Chrome, Opera, Safari
	return new XMLHttpRequest();
	}
	if (window.ActiveXObject) {
	// code for IE6, IE5
	return new ActiveXObject("Microsoft.XMLHTTP");
	}
	return null;
}

function processEntry(temp) {
	//extract the value entered
	temp = temp || window.event;
	var elem = temp.srcElement || temp.target;
	var str = elem.value; //ö
		elem.value = "";
		
	if (window.myStatus[1] == 0)
		speech("<p>You have not loaded a lesson!</p>");
	else {
	
	if (window.lesson[window.myStatus[0]][0] == 0) {
		if (checkAnswer(str, window.myStatus[0])) {
				textGreen();
				pickOutput(2,1);
				window.myStatus[0]++;
			} else { 
				textRed();
				ans = window.lesson[window.myStatus[0]][2];
				speech("<p><em>" + correctionOutput(ans,str) + 
				"</em></p>" + "<p>" + window.lesson[window.myStatus[0]+1][1] + "</p>");		
				window.myStatus[0]++;
			}
	
	} else if (window.lesson[window.myStatus[0]][0] == 2) {
			textGrey();
			pickOutput(2,1);
			window.myStatus[0]++;
	} else if (window.lesson[window.myStatus[0]][0] == 4) {
			textGrey();
			var percent = 100*window.myStatus[2]/window.myStatus[0];
			percent = Math.round(percent);
			checkAnswer(str, window.myStatus[0]);
			window.myStatus[0]++;
			endstr = "Good work! You finished the lesson and answered " + window.myStatus[2] +
			"/" + window.myStatus[0] + " (" + percent + "%) questions correctly. ";
			if (percent < 75) {
			endstr = endstr + "To maximize your learning, I recommend that you complete this " +
			"lesson again. Don't be discouraged - learning a language is hard work, " +
			"and if you put in more work now your efforts will be rewarded in the future! " +
			"Try this lesson again today or tomorrow before moving on.";
			} else {
			endstr = endstr + "Research shows that your brain needs time to absorb new " + 
			" information, and your learning is optimized if it is spread over time. So if you " +
			"are comfortable with what you have learned, come back tomorrow for your next " +
			"lesson. Otherwise, feel free to complete this lesson again. See you soon!";
			}
			ans = window.lesson[window.myStatus[0]-1][2];
			speech("<p><em>" + correctionOutput(ans,str) + 
			"</em></p> <p>" + endstr + "</p>");
			
		} else {
			if (checkAnswer(str, window.myStatus[0])) {
				textGreen();
				pickOutput(2,1);
				window.myStatus[0]++;
			} else { 
				if (window.lesson[window.myStatus[0]][0] == 1) {
					textRed();
					pickOutput(3,0);
				} else {
					textRed();
					pickOutput(3,1);
					window.myStatus[0]++;
				} // end last else
			} // else if incorrect
		} //end auto else
	
	} // end loaded else
} // function

function load(num) {
	window.myStatus[0] = 0;
	xmlhttp=GetXmlHttpObject();
	if (xmlhttp==null) {
		alert ("Your browser does not support XMLHTTP!");
  		return;
	}
	document.getElementById("txtHint").innerHTML="<center><img src=\"../img/loading.gif\"/></center>";
	var url="../php/lesson" + num + ".php";
	xmlhttp.onreadystatechange=stateChanged;
	xmlhttp.open("GET",url,true);
	xmlhttp.send(null);   
	window.myStatus[1] = num;
}

function validateEmail(email){
	var regEx = /^[\w\.\+-]{1,}\@([\da-zA-Z-]{1,}\.){1,}[\da-zA-Z-]{2,6}$/;
	if (!regEx.test(email)) {
		return false;
	} 
return true;
}

function createXmlHttpObject() {
  var req = null;
  try {
    req = new XMLHttpRequest(); //ie7, ff, safari
  }
  catch (e) {
    try {
      req = new ActiveXObject("Msxml2.XMLHTTP"); //later ie
    }
    catch (e) {
      try {
        req = new ActiveXObject("Microsoft.XMLHTTP") // earlier ie
      }
      catch (e) {
        // could not create XMLHttpRequest object
        return false;
      }
    }
  }
  return req;
}

function feedback() {
	var yemail=document.getElementById('posEmail').value;
	var ycomment=document.getElementById('posText').value;
	if((yemail=='') || (ycomment=='')){ 
		alert('You must enter all fields');
		return false; 
	}

	var params="feedback=1&email="+yemail+"&comment="+ycomment;
	//alert(params);
	if(validateEmail(yemail)){
		objXMLHttp=createXmlHttpObject();
		
		if (objXMLHttp==null) {
			alert ('Your browser does not support the XMLHttpRequest object!');
			return;
		}
		//alert(params);
		var url='../php/contact.php?'+params // prevent caching
		objXMLHttp.onreadystatechange = result;
		objXMLHttp.open('GET',url,true); // GET method
		objXMLHttp.send(null); // always use null for GET method
	} else {
		alert('Your Email address is not correct');
		return false;
	}
}

function result()
{
  if (objXMLHttp.readyState == 0)  {
    document.getElementById("status").innerHTML = "Sending mail, please wait...<br/><img src=\"../img/loading.gif\" />"; //uninitialized
  }
  else if(objXMLHttp.readyState == 1)  {
    document.getElementById("status").innerHTML = "Sending mail, please wait...<br/><img src=\"../img/loading.gif\" />"; //loading
  }
  else if(objXMLHttp.readyState == 2)  {
    document.getElementById("status").innerHTML = "Sending mail, please wait...<br/><img src=\"../img/images/indicator.gif\" /> "; //loaded
  }
  else if(objXMLHttp.readyState == 3)  {
    document.getElementById("status").innerHTML = "Sending mail, please wait...<br/><img src=\"../img/images/indicator.gif\" />"; //interactive
  }
  else if (objXMLHttp.readyState == 4 || objXMLHttp.readyState == "complete") {
    document.getElementById("status").innerHTML=objXMLHttp.responseText // completed
  }
} 



