


import System
import System.IO
import System.Xml
import System.Xml.XPath
import FormBuilder

import Microsoft.JScript


enum ControlType
{
  Form,
  HorizontalPanel,
  VerticalPanel,
  Button,
  TextBox,
  CheckBox,
  ComboBox,
  Label,
  ListBox
}

class NodeParser
{
  protected var node : XPathNavigator
  protected var nodeName : String
  protected var attributes : Attribute[]
  protected var children : NodeParser[]

  function get Name() : String { return nodeName }
  function get Attributes() : Attribute[] { return attributes }
  function get Children() : NodeParser[] { return children }
    
  function NodeParser(node : XPathNavigator)
  {
    this.node = node.Clone()
    ProcessNode()
  }
  
  protected function ProcessNode()
  {
    nodeName = node.Name
    if (node.HasAttributes)
      attributes = ParseAttributes()

    if (node.HasChildren)
      children = ParseChildren()
  }
  
  protected function ParseAttributes() : Attribute[]
  {
    var results = []
    node.MoveToFirstAttribute()
    do
    {
      results.push(new Attribute(node.Name, node.Value))
    } while(node.MoveToNextAttribute())

    node.MoveToParent()    
    return results
  }
  
  protected function ParseChildren() : NodeParser[]
  {
    var results = []
    node.MoveToFirstChild()
    do
    {
      results.push(new GenericControlNodeParser(node))
    } while(node.MoveToNext())
    
    return results
  }

  function ToString() : String
  {
    var text : String
    text = nodeName + ": " + attributes + "\n"
    for(var i in children)
      text += children[i] + "\n"
      
    return text
  }

  function Traverse(callBack : Function, level : int, data : Object)
  {
    callBack(this, true, level, data)

    for (var i : int in children)
      children[i].Traverse(callBack, level + 1, data)

    callBack(this, false, level, data)
  }

  function GetAttribute(name : String, defaultValue : String) : String
  {
    for (var i : int in attributes)
      if (attributes[i].Name == name)
        return attributes[i].Value
        
    return defaultValue
  }

  class Attribute
  {
    var Name : String
    var Value : String
    
    function Attribute(name : String, value : String)
    {
      Name = name
      Value = value
    }
    
    function ToString() : String
    {
      return Name + "=\"" + Value + "\""
    }
  }
}

class GenericControlNodeParser extends NodeParser implements IGenerateSource
{
  protected var control : IGenerateSource
  static protected var controlID : int = 0
  
  function GenericControlNodeParser (node : XPathNavigator)
  {
    super(node)
    
    CreateControl()
    if (control instanceof IGroup)
    {
      for (var i : int in children)
      {
        if (children[i] instanceof GenericControlNodeParser )
        {
          var childControl = GenericControlNodeParser (Object(children[i])).control
          IGroup(Object(control)).Add(IRectangle(Object(childControl)))
        }
      }
    }
  }

  function get Control() : IGenerateSource { return control }

  protected function CreateControl()
  {
    var width : int = int(GetAttribute("width", 0))
    var height : int = int(GetAttribute("height", 0))
    var padding : int = int(GetAttribute("padding", 8))
    var alignment : AlignmentType = AlignmentType(GetAttribute("align", "Left"))
    var stretch : StretchType = StretchType(GetAttribute("stretch", "None"))
    var text : String = GetAttribute("text", "")
    var identifier : String = GetAttribute("name", "control" + controlID++)
    
    switch(nodeName)
    {
    case "Button":
      control = new Button(identifier, text, width, height, stretch, alignment)
	  GenericControl(control).AddEvent("Click", "MessageBox.Show(\"" + identifier + "\", \"You clicked...\")");
      break

    case "Label":
      control = new Label(identifier, text, width, height, stretch, alignment)
      break

    case "CheckBox":
      control = new CheckBox(identifier, text, width, height, stretch, alignment)
	  GenericControl(control).AddEvent("Click", "MessageBox.Show(\"" + identifier + " is \" + " + identifier +".Checked , \"Checkbox clicked...\")");
      break

    case "TextBox":
      control = new TextBox(identifier, text, width, height, stretch, alignment)
      break

    case "ComboBox":
      control = new ComboBox(identifier, text, width, height, stretch, alignment)
      break

    case "ListBox":
      control = new ListBox(identifier, text, width, height, stretch, alignment)
      break
    case "Form":
      control = new Form(identifier, text, padding)
      break
    
    case "VerticalPanel":
      control = new VerticalPanel(identifier, alignment, padding)
      break
    
    case "HorizontalPanel":
      control = new HorizontalPanel(identifier, alignment, padding)
      break
    }
    
  }
  
  
  function get Identifier() : String { return control.Identifier }
  function get TypeName() : String { return control.TypeName }
    
  function Declaration(prefix : String) : String { return control.Declaration(prefix) }
  function Initialisation(prefix : String) : String { return control.Initialisation(prefix) }
  function SupportingCode(prefix : String) : String { return control.SupportingCode(prefix) }
}

function PrintNode(node : NodeParser, pre : boolean, level : int, data : Object)
{
  var indent = ""
  for (var i = 0; i < level; i++)
    indent += "  "

  if (pre)
  {
    if (node instanceof GenericControlNodeParser)
    {
      IGroup(Object(GenericControlNodeParser(Object(node)).Control)).LayoutChildren()
      print(IGenerateSource(Object(node)).Declaration(indent))
    }
    else
    {
      print(indent + "Node " + node.Name)
      print(indent + " Attributes: " + Array(node.Attributes).join(", "))
    }
  }
  else
  {
    if (node instanceof GenericControlNodeParser)
      print(IGenerateSource(Object(node)).Initialisation(indent))
    else
      print(indent + "End of " + node.Name)
  }
}

var args : String[] = Environment.GetCommandLineArgs()
if (args.length < 2)
{
  print("Usage: " + args[0] + " <xmlfile>")
  Environment.Exit(1)
}

var inputFile : String = args[1]
if (inputFile.indexOf(".xml") == -1)
  inputFile += ".xml"

var outputFile : String = inputFile.replace(/\.xml/, ".exe")
var sourceFile : String = inputFile.replace(/\.xml/, ".js")

var xdoc : XPathDocument = new XPathDocument(inputFile)
var navigator : XPathNavigator = xdoc.CreateNavigator()
navigator.MoveToFirstChild()
var root = new GenericControlNodeParser(navigator)

var layout : IGroup = IGroup(Object(GenericControlNodeParser(Object(root)).Control))
var generator : IGenerateSource = IGenerateSource(Object(root))

layout.LayoutChildren()

var text : String = root.Declaration()
text += root.Initialisation()

var fInfo :FileInfo = new FileInfo(sourceFile)
var fc : String = "//\r\n// Code generated by xForm\r\n// \r\n" 
fc += "// \r\n// Generated : " + new Date().toString() + "\r\n// \r\n"
fc += "// Source XML: " + fInfo.DirectoryName + "\\" + inputFile + "\r\n"
fc += "// This file : " + fInfo.DirectoryName + "\\" + sourceFile + "\r\n"
fc += "// \r\n"
fc += "// NOTE: xmlForm generates click event handlers automatically \r\n"
fc += "//       for Button and CheckBox controls\r\n// \r\n"
fc += "// Compile this program using the command: \r\n// \r\n"
fc += "//   jsc /t:winexe " + sourceFile + " \r\n// \r\n"
fc +=text;
text=fc;
fc="";

var compileOK :Boolean=true;
try
{
	var stream : StreamWriter = File.CreateText(sourceFile)
	stream.Write(text)
}
catch(e)
{
	print("Error saving file:\n" + e)
	compileOK=false;
}
finally
{
	if (stream)
		stream.Close()
}
if (compileOK) {
	print("Source written to " + sourceFile)
	print("\n* Compile using the command:\n\tjsc /t:winexe " + sourceFile + " \n\n")
}


