/*
This software is copyright 2009 Matthew Wilson matthew@wilson.org
and available under the Artistic License 2 ("AL2") as documented at
http://jsmeta.googlecode.com
*/

var ugrammar_input_lastVal = '';
var ugrammar_output_text = '';
var ugrammar_last_output_text = '';
var outputArea, inputArea, grammarInputArea, notificationArea;

var Print;
if (debugMode) {
  Print = function(outputText) {
    try {
      (notificationArea || (notificationArea = window.frames["frame_mgrammar_error"].editArea.textarea)).value += outputText.toString() + '\n';
    } catch(e) {
      // just ignore a failure here.
    }
  }
} else {
  Print = function(outputText) {
    try {
      (notificationArea || (notificationArea = window.frames["frame_mgrammar_error"].editArea.textarea)).value = outputText.toString();
    } catch(e) {
      // just ignore a failure here.
    }
  }
};

// initialisation
editAreaLoader.init({
  id: "ugrammar_input"
  ,start_highlight: false
  ,smooth_selection: false
  ,allow_resize: "no"
  ,font_family: "consolas, lucida console, monospace, courier new"
  ,font_size: 12
  ,max_undo: 100
  ,word_wrap: true
	,replace_tab_by_spaces: 4
  ,keyup_callback: "ugrammar_input_changed"
  ,browsers: 'all'
  ,toolbar: "search, go_to_line, fullscreen, word_wrap, |, undo, redo"
  ,allow_toggle: false
  ,show_line_colors: false
  ,language: "en"
//,EA_load_callback: "ugrammar_input_loaded"
});

editAreaLoader.init({
  id: "mgrammar_input"  // id of the textarea to transform  
  ,start_highlight: false
  ,smooth_selection: false
  ,allow_toggle: false
  ,is_editable: true
  ,allow_resize: "no"
	,replace_tab_by_spaces: 4
  ,font_family: "consolas, lucida console, monospace, courier new"
  ,font_size: 12
  ,max_undo: 100
  ,word_wrap: true
  ,keyup_callback: "ugrammar_input_changed"
  ,browsers: 'all'
  ,is_multi_files: false
  ,show_line_colors: false
  ,language: "en"
});

editAreaLoader.init({
  id: "ugrammar_output"  // id of the textarea to transform  
  ,start_highlight: false
  ,smooth_selection: false
  ,allow_toggle: false
  ,is_editable: true
  ,allow_resize: "no"
  ,font_family: "consolas, lucida console, monospace, courier new"
  ,font_size: 12
  ,max_undo: 100
  ,word_wrap: true
  ,browsers: 'all'
  ,is_multi_files: false
  ,show_line_colors: false
  ,language: "en"
});


editAreaLoader.init({
  id: "mgrammar_error"  // id of the textarea to transform  
  ,start_highlight: false
  ,smooth_selection: false
  ,allow_toggle: false
  ,is_editable: true
  ,allow_resize: "yes"
  ,font_family: "consolas, lucida console, monospace, courier new"
  ,font_size: 12
  ,max_undo: 100
  ,word_wrap: true
  ,browsers: 'all'
  ,is_multi_files: false
  ,show_line_colors: false
  ,language: "en"
});

function ugrammar_input_changed(){
  var new_val = editAreaLoader.getValue('ugrammar_input');
  if (new_val != ugrammar_input_lastVal || editAreaLoader.getValue('mgrammar_input') != lastUGrammarInput) {
    ugrammar_input_lastVal = new_val;
    var r;
    if (continueCurrentParse) {
      if (parseRunning) {
        continueCurrentParse = false;
        var parseRunnerTimeout = function() {
          continueCurrentParse = true;
          var startTime = new Date().getTime();
          r = runMGrammar();
          ugrammar_output_text = ((new Date()).getTime() - startTime) + ' ms\n' + (r.reTests ? r.reTests+'\n' : '') + r.result;
          if (ugrammar_last_output_text!=ugrammar_output_text) {
            ugrammar_last_output_text = (outputArea || (outputArea = window.frames["frame_ugrammar_output"].editArea.textarea)).value = ugrammar_output_text;
            outputArea.textareaFocused = true;
            (inputArea || (inputArea = window.frames["frame_ugrammar_input"].editArea.textarea)).Focused = true;
          }
        };
        setTimeout(parseRunnerTimeout, 10);
      } else {
        var startTime = new Date().getTime();r = runMGrammar();
        ugrammar_output_text = ((new Date()).getTime() - startTime) + ' ms\n' + (r.reTests ? r.reTests+'\n' : '') + r.result;
        if (ugrammar_last_output_text!=ugrammar_output_text) {
          ugrammar_last_output_text = (outputArea || (outputArea = window.frames["frame_ugrammar_output"].editArea.textarea)).value = ugrammar_output_text;
          outputArea.textareaFocused = true;
          (inputArea || (inputArea = window.frames["frame_ugrammar_input"].editArea.textarea)).Focused = true;
        }
      }
    }
  }
}

var mgrammar_input_lastVal = '';
var lastUGrammarInput = '';
var lastDynamicParser;
var lastParseContext;

function runMGrammar() {
  var inputStr = ugrammar_input_lastVal;
  var grammarInputStr = (grammarInputArea || (grammarInputArea = window.frames["frame_mgrammar_input"].editArea.textarea)).value;
  if (grammarInputStr == lastUGrammarInput && typeof(lastDynamicParser)!='undefined') {
    var grammarGenerator = Module.Exec(lastDynamicParser);
    lastParseContext.__Init(inputStr);
    var parseResult = Module.Parse(grammarGenerator, inputStr, lastParseContext);
    ignoreDisqualifyingREs = false;
    if (parseResult.outcome) {
      Print(' \n');
    } else {
      /*if (debugMode && debugTrace && !traceOn) {
        lastParseContext.__Init(inputStr);
        ignoreDisqualifyingREs = traceOn = true;
        parseResult = Module.Parse(grammarGenerator, inputStr, lastParseContext);
        ignoreDisqualifyingREs = traceOn = false;
      }*/
      Print('Error: ' + typeof(parseResult.errorMsg)=='undefined' ? 'Unknown' : parseResult.errorMsg);
      parseResult.result = '';
    }
    return parseResult;
  }
  var ourFinalResult = Module.Parse(function(){
    return loadAndRunMGrammar(grammarInputStr, inputStr)
  });
  if (!ourFinalResult.outcome) {
    Print('Error: ' + typeof(ourFinalResult.errorMsg)=='undefined' ? 'Unknown' : ourFinalResult.errorMsg);
    lastUGrammarInput = '';
    ourFinalResult.result = '';
  }
  return ourFinalResult;
}

function loadAndRunMGrammar(grammarInputStr, inputStr) {
  JSMetaPadInputString = inputStr;
  Print('Parsing and compiling MGrammar input\n');
  lastUGrammarInput = grammarInputStr;
  
  Module(function Microsoft__M__Grammar(l) {
    l.__Language(MGrammar).Export();
  });
  return Module.Exec(function runit(l) {
    l.__Import('Microsoft.M.Grammar');
    l.__Init(grammarInputStr);
    return [l.Microsoft.M.Grammar.MGrammar.Main(), l];
  });
}


// written by Dean Edwards, 2005
// with input from Tino Zijdel - crisp@xs4all.nl
// http://dean.edwards.name/weblog/2005/10/add-event/
function addEvent(element, type, handler)
{
	if (element.addEventListener)
		element.addEventListener(type, handler, false);
	else
	{
		if (!handler.DeAnEdWaRdSguid) handler.DeAnEdWaRdSguid = addEvent.guid++;
		if (!element.events) element.events = {};
		var handlers = element.events[type];
		if (!handlers)
		{
			handlers = element.events[type] = {};
			if (element['on' + type]) handlers[0] = element['on' + type];
			element['on' + type] = handleEvent;
		}
	
		handlers[handler.DeAnEdWaRdSguid] = handler;
	}
}
addEvent.guid = 1;

function removeEvent(element, type, handler)
{
	if (element.removeEventListener)
		element.removeEventListener(type, handler, false);
	else if (element.events && element.events[type] && handler.DeAnEdWaRdSguid)
		delete element.events[type][handler.DeAnEdWaRdSguid];
}

function handleEvent(event)
{
	event = event || fixEvent(window.event);
	var returnValue = true;
	var handlers = this.events[event.type];

	for (var i in handlers)
	{
		if (!Object.prototype[i])
		{
			this.DeAnEdWaRdShandler = handlers[i];
			if (this.DeAnEdWaRdShandler(event) === false) returnValue = false;
		}
	}

	if (this.DeAnEdWaRdShandler) this.DeAnEdWaRdShandler = null;

	return returnValue;
}

function fixEvent(event)
{
	event.preventDefault = fixEvent.preventDefault;
	event.stopPropagation = fixEvent.stopPropagation;
	return event;
}
fixEvent.preventDefault = function()
{
	this.returnValue = false;
}
fixEvent.stopPropagation = function()
{
	this.cancelBubble = true;
}

// This little snippet fixes the problem that the onload attribute on the body-element will overwrite
// previous attached events on the window object for the onload event
if (!window.addEventListener)
{
	document.onreadystatechange = function()
	{
		if (window.onload && window.onload != handleEvent)
		{
			addEvent(window, 'load', window.onload);
			window.onload = handleEvent;
		}
	}
}

function isRightClick(e) {
  e = e || window.event;
  return (e.which && e.which==3) || (e.button && e.button==2);
}

function checkHaltParse(e) {
  alert('checking whether to halt the parse');
  if (parseRunning/* && isRightClick(e)*/) {
    continueCurrentParse = false;
    emitCoreDump = true;
  }
}

function disableHighlights() {
  window.frames["frame_ugrammar_input"].editArea.disable_highlight();
  window.frames["frame_mgrammar_input"].editArea.disable_highlight();
  window.frames["frame_ugrammar_output"].editArea.disable_highlight();
  window.frames["frame_mgrammar_error"].editArea.disable_highlight();
}

addEvent(window, 'load', function() {
  setTimeout(disableHighlights, 600);
  setTimeout(ugrammar_input_changed, 200);
  //addEvent(window, 'mousedown', checkHaltParse);
});



