function root_Loaded(sender, args) {
    new tileText(sender);
}

function tileEntry(value, offset) {
    this.value = value;
    this.offset = offset;
}

function tileText(rootCanvas) {

    // Hook up the button event handlers
    var button = rootCanvas.findName("button");
    this.setCallback(button, "mouseEnter", this.handleMouseEnter); 
    this.setCallback(button, "mouseLeave", this.handleMouseLeave); 
    this.setCallback(button, "mouseLeftButtonUp", this.handleMouseUp); 
    this.setCallback(button, "mouseLeftButtonDown", this.handleMouseDown); 
    
    // Initialize the tiles
    this.tileEntries = new Array(26);
    this.setupTileEntries();
    
    // Make the HTML text input visible
    var textInput = document.getElementById("textInput");
    textInput.style.visibility = "visible";
    
    // Process teh default string
	this.processString(textInput.value);
}

tileText.prototype.handleMouseEnter = function(sender, eventArgs) {
    var buttonBG = sender.findName("buttonBG");
    buttonBG.fill = "#FFa0a0a0";
}

tileText.prototype.handleMouseLeave = function(sender, eventArgs) {
	var buttonBG = sender.findName("buttonBG");
	buttonBG.fill = "#FF808080";
}

tileText.prototype.handleMouseUp = function(sender, eventArgs) {
	var buttonBG = sender.findName("buttonBG");
	buttonBG.fill = "#FFa0a0a0";
	
	var textInput = document.getElementById("textInput");
	this.processString(textInput.value);
}

tileText.prototype.handleMouseDown = function(sender, eventArgs) {
	var buttonBG = sender.findName("buttonBG");
	buttonBG.fill = "#FF606060";
}

// Takes a string and turns it into tiles
tileText.prototype.processString = function(text) {
    this.clearTree();
    
    // Protect from characters that our XML parser doesn't like
    text = text.replaceAll("<", "_");
    text = text.replaceAll("&", "_");
    text = text.replaceAll("'", "_");
    text = text.toUpperCase();
    
    // Determine if this will fit in one line
    var multiline = false;
    var top = 65;
    if (text.length > 11) {
        multiline = true;
        top = 25;
    }
    
    // If we're multiline, determine how to break the lines
    var breakIndex = 0;
    if (multiline) {
        var spaceIndex = text.lastIndexOf(' ');
        
        if ((spaceIndex > -1) && (text.length - spaceIndex < 11)){
            breakIndex = spaceIndex;
        }   
        if (breakIndex > 11 || text.length - breakIndex > 11) {
            breakIndex = 11;
        }
    }
    
    var leftPosition; 
    var leftPosition2;
    
    if (multiline) {
        leftPosition = (600 - (breakIndex * 52)) / 2;
        leftPosition2 = ((600 - (text.length - breakIndex) * 52)) / 2;
    }
    else {
        leftPosition = (600 - (text.length * 52)) / 2;
    }
    
    for (var i = 0; i < text.length; i++) {
        if (multiline && i == breakIndex) {
           top = 100; 
           leftPosition = leftPosition2;
        }
        if (text.charAt(i) == ' ') {
            leftPosition += 10;
            continue;
        }
        var charCode = text.charCodeAt(i) - 65;
        
        if (charCode < 0 || charCode > 25) {
            this.addTile(i, text.charAt(i), (Math.floor(Math.random()*8)) + 1, top + (Math.floor(Math.random()*9)), leftPosition, "", 17, "00:00:0" + ((i + 1) * .2).toString().substr(0,3));
        }
        else {
            this.addTile(i, text.charAt(i), (Math.floor(Math.random()*8)) + 1, top + (Math.floor(Math.random()*9)), leftPosition, this.tileEntries[charCode].value, 12 + this.tileEntries[charCode].offset, "00:00:0" + ((i + 1) * .2).toString().substr(0,3));
        }
        leftPosition += 52 + Math.floor(Math.random()*2);
    }
}

tileText.prototype.addTile = function(tileNumber, letter, grainIndex, top, left, value, letterOffset, beginTime) {
    //this is the template for tiles
    // $0: index of this tile
    // $1: letter on this tile
    // $2: image file for this tile
    // $3: top coordinate this tile
    // $4: left coordinate of this tile
    // $5: point value of this tile
    // $6: left letter offset
    xamlString =         "<Canvas xmlns='http://schemas.microsoft.com/client/2007' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' x:Name='tile$0' Canvas.Top='0' Canvas.Left='0' RenderTransformOrigin='0.5,0.5' Height='53' Width='53'>";
    xamlString = xamlString + "<Canvas x:Name='tileTarget$0' Canvas.Top='-100'>";
    xamlString = xamlString + "  <Canvas.Triggers>";
	xamlString = xamlString + "  <EventTrigger RoutedEvent='FrameworkElement.Loaded'>";
	xamlString = xamlString + "  <BeginStoryboard>";
	xamlString = xamlString + "  <Storyboard BeginTime='$7'>";
	xamlString = xamlString + "  <DoubleAnimationUsingKeyFrames BeginTime='00:00:00' Storyboard.TargetName='tileTarget$0' Storyboard.TargetProperty='(Canvas.Left)'>";
	xamlString = xamlString + "  <SplineDoubleKeyFrame KeyTime='00:00:00.6' KeySpline='.75,0,0,.75' Value='$4'/>";
	xamlString = xamlString + "  </DoubleAnimationUsingKeyFrames>";
	xamlString = xamlString + "  <DoubleAnimationUsingKeyFrames BeginTime='00:00:00' Storyboard.TargetName='tileTarget$0' Storyboard.TargetProperty='(Canvas.Top)'>";
	xamlString = xamlString + "  <SplineDoubleKeyFrame KeyTime='00:00:00.6' KeySpline='.75,0,0,.75' Value='$3'/>";
	xamlString = xamlString + "  </DoubleAnimationUsingKeyFrames>";
	xamlString = xamlString + "  </Storyboard>";
	xamlString = xamlString + "  </BeginStoryboard>";
	xamlString = xamlString + "  </EventTrigger>";
    xamlString = xamlString + "  </Canvas.Triggers>";
    xamlString = xamlString + "  <Image Source='images/$2.png' />";
    xamlString = xamlString + "  <TextBlock Canvas.Top='9' Canvas.Left='$6' FontFamily='Arial' FontSize='34' FontWeight='bold' Text='$1' />";
    xamlString = xamlString + "  <TextBlock Canvas.Top='36' Canvas.Left='37.5' FontFamily='Arial' FontSize='12' FontWeight='bold' Text='$5' />";
    xamlString = xamlString + "</Canvas>";
    xamlString = xamlString + "</Canvas>";
    
    xamlString = xamlString.replaceAll("$0", tileNumber);
    xamlString = xamlString.replaceAll("$1", letter);
    xamlString = xamlString.replaceAll("$2", grainIndex);
    xamlString = xamlString.replaceAll("$3", top);
    xamlString = xamlString.replaceAll("$4", left);
    xamlString = xamlString.replaceAll("$5", value);
    xamlString = xamlString.replaceAll("$6", letterOffset);
    xamlString = xamlString.replaceAll("$7", beginTime);
    
    var wpfeControl = document.getElementById("wpfeControl1");
    var tile = wpfeControl.createFromXaml(xamlString);
    wpfeControl.findName("root").children.add(tile);
}

// Removes the current tiles so that a new string can be processed
tileText.prototype.clearTree = function() {
    var wpfeControl = document.getElementById("wpfeControl1");
    var root = wpfeControl.findName("root");
    
    while (root.children.getItem(root.children.count - 1).name != "button") {
            root.children.removeAt(root.children.count - 1);
    }
}

// Initializes the tile array
tileText.prototype.setupTileEntries = function() {
    this.tileEntries[0] = new tileEntry(1, 1);
    this.tileEntries[1] = new tileEntry(3, 0);
    this.tileEntries[2] = new tileEntry(3, 0);
    this.tileEntries[3] = new tileEntry(2, 0);
    this.tileEntries[4] = new tileEntry(1, 0);
    this.tileEntries[5] = new tileEntry(4, 0);
    this.tileEntries[6] = new tileEntry(2, 0);
    this.tileEntries[7] = new tileEntry(4, 1);
    this.tileEntries[8] = new tileEntry(1, 8);
    this.tileEntries[9] = new tileEntry(8, 1);
    this.tileEntries[10] = new tileEntry(5, 0);
    this.tileEntries[11] = new tileEntry(1, 2);
    this.tileEntries[12] = new tileEntry(3, -2);
    this.tileEntries[13] = new tileEntry(1, 0);
    this.tileEntries[14] = new tileEntry(1, 0);
    this.tileEntries[15] = new tileEntry(3, 0);
    this.tileEntries[16] = new tileEntry(10, -2);
    this.tileEntries[17] = new tileEntry(1, 0);
    this.tileEntries[18] = new tileEntry(1, 0);
    this.tileEntries[19] = new tileEntry(1, 1);
    this.tileEntries[20] = new tileEntry(1, 0);
    this.tileEntries[21] = new tileEntry(4, 1);
    this.tileEntries[22] = new tileEntry(4, -3);
    this.tileEntries[23] = new tileEntry(8, 1);
    this.tileEntries[24] = new tileEntry(4, 2);
    this.tileEntries[25] = new tileEntry(10, 2);
}

// Routes a WPF/E event to a local handler instance
tileText.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[eventName] = "javascript:" + callbackName;
}

// Handles the JoltControl's error event  
function ErrorHandler(line, column, hr, errorString) {
    str = errorString + " at ("+line+", "+column+")";
    alert("Error: " + str);
}

// Replaces all instances of the given substring.
String.prototype.replaceAll = function(strTarget, strSubString) {
    var strText = this;
    var intIndexOfMatch = strText.indexOf( strTarget );
 
    // Keep looping while an instance of the target string
    // still exists in the string.
    while (intIndexOfMatch != -1) {
        // Relace out the current instance.
        strText = strText.replace( strTarget, strSubString )

        // Get the index of any next matching substring.
        intIndexOfMatch = strText.indexOf( strTarget );
    }
 
    // Return the updated string with ALL the target strings
    // replaced out with the new substring.
    return( strText );
}