var eng;

function loaded(sender, args) 
{
  eng = new engine(sender);
}

function delegate(target, callback) {
	var func = function() {
		callback.apply(target, arguments);
	}
	return func;
}

function colChar(hits, letter)
{
  this.hits = hits;
  this.letter = letter;
  this.active = true;
}

colChar.prototype.addHit = function(maxHits)
{
  this.hits++;
  if (this.hits >= maxHits && this.active == true && this.letter.length > 0)
  {
    this.active = false;
    return true;
  }
  else
  {
    return false;
  }
}

function engine(sender)
{
  this.canvas = sender.findName("root");
  this.prompt = sender.findName("prompt");
  this.cursor = sender.findName("cursor");

  this.host = sender.getHost();
  this.stop = false;
  this.callback = null;
  this.glyphCount = 0;
  this.letterCount = 18;
  this.colCount = 29;
  this.text = "";
  this.cols = new Array();
  this.maxHits = 3;

  this.setCallback(this.canvas, "keydown", delegate(this, this.keyDown));
}

engine.prototype.startGlyphs = function()
{
  if (this.addGlyphs())
  {
    var timeout = Math.floor(Math.random()*400);
    this.callback = setTimeout('eng.startGlyphs()', timeout);
  }
}

engine.prototype.addGlyphs = function()
{
  var cont = true;
  this.glyphCount++;
  var col = Math.floor(Math.random()*this.colCount);
  if (this.cols[col].addHit(this.maxHits))
  {
    this.canvas.children.add(this.host.content.createFromXaml(this.genLtrGlyphs(col)));
    this.activeLetters--;
    if (this.activeLetters <= 0) cont = false;
  }
  else if (this.cols[col].active == true)
  {
    this.canvas.children.add(this.host.content.createFromXaml(this.genGlyphs(col)));
    this.setCallback(this.canvas.findName("Sb" + this.glyphCount), "completed", delegate(this, this.removeGlyphs));
  }
  return cont;
}

engine.prototype.removeGlyphs = function(sender, args)
{
  var name = sender.Name;
  var num = parseInt(name.replace("Sb",""));
  var c = this.canvas.findName(name.replace("Sb","C"));
  this.canvas.children.remove(c);
}

engine.prototype.genLtrGlyphs = function(col)
{
  var left = col * 14; 
  var row = this.letterCount / 2;
  var xaml = "<Canvas Width='14' Height='300' Canvas.Left='" + left + "' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>";

  for (i = 0; i < (row - 1); i++)
  {
        var letter = String.fromCharCode(Math.floor(Math.random()*26) + 65);
	xaml += this.getGlyphsXaml(letter, i);
  }
  
  xaml += this.getLtrGlyphsXaml(this.cols[col].letter, row - 1);

  xaml += '<Canvas.Background>' +
	  '<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">' +
          '<GradientStop x:Name="Gb' + this.glyphCount + 'b" Color="#ff000000" Offset="-0.1" />' +
          '<GradientStop x:Name="Gb' + this.glyphCount + 't" Color="#00000000" Offset="0.0" />' +
          '<GradientStop Color="#00000000" Offset="1.0" />' +
      	  '</LinearGradientBrush>' +
	  '</Canvas.Background>' +
          '<Canvas.Triggers>' +
          '<EventTrigger RoutedEvent="Canvas.Loaded">' +
          '<BeginStoryboard>' +
          '<Storyboard Storyboard.TargetProperty="Offset">' +
          '<DoubleAnimation Storyboard.TargetName="Gb' + this.glyphCount + 'b" From="-0.1" To="1" Duration="0:0:2.235" />' +
          '<DoubleAnimation Storyboard.TargetName="Gb' + this.glyphCount + 't" From="0.0" To="1.1" Duration="0:0:2.235" />' +
         '</Storyboard>' +
         '</BeginStoryboard>' +
         '</EventTrigger>' +
         '</Canvas.Triggers>' +
  	 '</Canvas>';

  return xaml; 
}

engine.prototype.genGlyphs = function(col)
{
  var left = col * 14; 
  var xaml = "<Canvas x:Name='C" + this.glyphCount + "' Width='14' Height='300' Canvas.Left='" + left + "' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>";

  for (i = 0; i < this.letterCount; i++)
  {
        var letter = String.fromCharCode(Math.floor(Math.random()*26) + 65);
	xaml += this.getGlyphsXaml(letter, i);
  }

  xaml += '<Canvas.Background>' +
	  '<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">' +
          '<GradientStop x:Name="Gb' + this.glyphCount + 'b" Color="#ff000000" Offset="-0.1" />' +
          '<GradientStop x:Name="Gb' + this.glyphCount + 't" Color="#00000000" Offset="0.0" />' +
          '<GradientStop Color="#00000000" Offset="1.0" />' +
      	  '</LinearGradientBrush>' +
	  '</Canvas.Background>' +
          '<Canvas.Triggers>' +
          '<EventTrigger RoutedEvent="Canvas.Loaded">' +
          '<BeginStoryboard>' +
          '<Storyboard Storyboard.TargetProperty="Offset">' +
          '<DoubleAnimation Storyboard.TargetName="Gb' + this.glyphCount + 'b" From="-0.1" To="1" Duration="0:0:2.235" />' +
          '<DoubleAnimation Storyboard.TargetName="Gb' + this.glyphCount + 't" From="0.0" To="1.1" Duration="0:0:2.235" />' +
         '</Storyboard>' +
         '</BeginStoryboard>' +
         '</EventTrigger>' +
         '</Canvas.Triggers>' +
  	 '</Canvas>';

  return xaml;
}

engine.prototype.getLtrGlyphsXaml = function(letter, num)
{
  var top = (num * 17) - 5;
  var id = num + (this.glyphCount * this.letterCount);
  var rate = 0.125;
  var offset1 = 0.1 - (rate * num * 4);
  var offset2 = 0.0 - (rate * num * 4);
  var duration1 = 0.2 + (rate * num);
  var duration2 = 0.25 + (rate * num);
  var name = "";
  if (num + 1 == this.letterCount) name = 'x:Name="Sb' + this.glyphCount + '"';

  return '<Glyphs Canvas.Top="' + top + '" UnicodeString="' + letter + '" FontUri="ELECTROH.TTF" FontRenderingEmSize="24">' + 
	 '<Glyphs.Fill>' +
	 '<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">' +
         '<GradientStop x:Name="G' + id + '2" Color="#ff94FFAB" Offset="' + offset2 + '" />' +
         '<GradientStop x:Name="G' + id + '1" Color="#00000000" Offset="' + offset1 + '" />' +
      	 '</LinearGradientBrush>' +
	 '</Glyphs.Fill>' +
         '<Glyphs.Triggers>' +
         '<EventTrigger RoutedEvent="Glyphs.Loaded">' +
         '<BeginStoryboard>' +
         '<Storyboard ' + name + ' Storyboard.TargetProperty="Offset">' +
         '<DoubleAnimation Storyboard.TargetName="G' + id + '1" From="' + offset1 + '" To="1" Duration="0:0:' + duration1 + '" />' +
         '<DoubleAnimation Storyboard.TargetName="G' + id + '2" From="' + offset2 + '" To="1" Duration="0:0:' + duration2 + '" />' +
         '</Storyboard>' +
         '</BeginStoryboard>' +
         '</EventTrigger>' +
         '</Glyphs.Triggers>' +
	 '</Glyphs>';

}

engine.prototype.getGlyphsXaml = function(letter, num)
{
  var top = (num * 17) - 5;
  var id = num + (this.glyphCount * this.letterCount);
  var rate = 0.125;
  var offset1 = 0.1 - (rate * num * 4);
  var offset2 = 0.0 - (rate * num * 4);
  var offset3 = -0.5 - (rate * num * 4);
  var offset4 = -0.6 - (rate * num * 4);
  var offset5 = -3.6 - (rate * num * 4);
  var duration1 = 0.2 + (rate * num);
  var duration2 = 0.25 + (rate * num);
  var duration3 = 0.35 + (rate * num);
  var duration4 = 0.4 + (rate * num);
  var duration5 = 3.1 + (rate * num);
  var name = "";
  if (num + 1 == this.letterCount) name = 'x:Name="Sb' + this.glyphCount + '"';

  return '<Glyphs Canvas.Top="' + top + '" UnicodeString="' + letter + '" FontUri="ELECTROH.TTF" FontRenderingEmSize="24">' + 
	 '<Glyphs.Fill>' +
	 '<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">' +
         '<GradientStop x:Name="G' + id + '5" Color="#00000000" Offset="' + offset5 + '" />' +
         '<GradientStop x:Name="G' + id + '4" Color="#ff007300" Offset="' + offset4 + '" />' +
         '<GradientStop x:Name="G' + id + '3" Color="#ff94FFAB" Offset="' + offset3 + '" />' +
         '<GradientStop x:Name="G' + id + '2" Color="#ff94FFAB" Offset="' + offset2 + '" />' +
         '<GradientStop x:Name="G' + id + '1" Color="#00000000" Offset="' + offset1 + '" />' +
      	 '</LinearGradientBrush>' +
	 '</Glyphs.Fill>' +
         '<Glyphs.Triggers>' +
         '<EventTrigger RoutedEvent="Glyphs.Loaded">' +
         '<BeginStoryboard>' +
         '<Storyboard ' + name + ' Storyboard.TargetProperty="Offset">' +
         '<DoubleAnimation Storyboard.TargetName="G' + id + '1" From="' + offset1 + '" To="1" Duration="0:0:' + duration1 + '" />' +
         '<DoubleAnimation Storyboard.TargetName="G' + id + '2" From="' + offset2 + '" To="1" Duration="0:0:' + duration2 + '" />' +
         '<DoubleAnimation Storyboard.TargetName="G' + id + '3" From="' + offset3 + '" To="1" Duration="0:0:' + duration3 + '" />' +
         '<DoubleAnimation Storyboard.TargetName="G' + id + '4" From="' + offset4 + '" To="1" Duration="0:0:' + duration4 + '" />' +
         '<DoubleAnimation Storyboard.TargetName="G' + id + '5" From="' + offset5 + '" To="1" Duration="0:0:' + duration5 + '" />' +
         '</Storyboard>' +
         '</BeginStoryboard>' +
         '</EventTrigger>' +
         '</Glyphs.Triggers>' +
	 '</Glyphs>';
}

engine.prototype.setCallback = function(target, eventName, callback) {
	if (!window.methodIndex)
		window.methodIndex = 0;
	
	var callbackName = "uniqueCallback" + (window.methodIndex++);
	var controller = this;
	var func = function() {
		callback.apply(controller, arguments);
	}
	
	eval(callbackName + " = func;");
	target.addEventListener(eventName,callbackName);
}

engine.prototype.keyDown = function(sender, args)
{
  var start = false;
  switch (args.key)
  {
    case 1:
      this.deleteLetter();
      break;
    case 3:
      start = true;
      break;
    case 9:
      this.addSpace();
      break;
    default:
      this.addLetter(args.key, args.shift);
      break;
  }

  if (start == false)
  {
    this.prompt.Text = "Name>" + this.text;
    if (this.text.length >= this.colCount)
    {
      this.cursor.Foreground = "#00000000";
    }
    else
    {
      this.cursor.Foreground = "#ff94FFAB";
    }
  }
  else
  {
    this.cursor.Foreground = "#00000000";	
    this.prompt.Opacity = 0;
    this.activeLetters = this.text.length;

    var start = Math.floor((this.colCount - this.text.length) / 2);

    for (i = 0; i < this.colCount; i++)
      this.cols[i] = new colChar(0, this.text.charAt(i - start));
    this.startGlyphs();
  }
  
}

engine.prototype.setCursor = function(visible)
{
   if (visible) 
    this.cursor.Foreground = "#ff94FFAB";
   else
    this.cursor.Foreground = "#00000000";
}

engine.prototype.addLetter = function(letter, shift)
{
    if (this.text.length < this.colCount)
    {
      if (letter >= 30 && letter <= 55)
      {
         if (shift == true) offset = 35;
         else offset = 67;
         this.text += String.fromCharCode(letter + offset);
         this.cursor.SetValue("Canvas.Left", this.cursor.GetValue("Canvas.Left") + 9.5);
      } 
      else if (letter >= 20 && letter <= 29 && !shift) 
      {
         letter = letter % 20;
         this.text += letter.toString();
         this.cursor.SetValue("Canvas.Left", this.cursor.GetValue("Canvas.Left") + 9.5);
      }
    }
}

engine.prototype.addSpace = function()
{
    if (this.text.length < this.colCount)
    {
      this.text += " ";
      this.cursor.SetValue("Canvas.Left", this.cursor.GetValue("Canvas.Left") + 9.5);
    }
}

engine.prototype.deleteLetter = function()
{
  var len = this.prompt.Text.length;
  if (len > 5)
  {
    this.text = this.text.substring(0,this.text.length - 1);
    this.cursor.SetValue("Canvas.Left", this.cursor.GetValue("Canvas.Left") - 9.5);
  }
}
