public MetadataFileEditor(MetadataFile metadataFile) : base(metadataFile.GetFullPath()) {
			//
			// The InitializeComponent() call is required for Windows Forms designer support.
			//
			InitializeComponent();

			_metadataFile = metadataFile;
			txtDocument.Enabled = true;
		}
		// TODO: Notify other objects when a metadata file is added or removed
		
		#region Overridden properties and methods
		new public int Add(MetadataFile val)
		{
			if (this.Project != null) {
				val.SetProject(this.Project);
			}
			if ( !this.Contains(val) ) {
				if (this.Project != null && !Project.IsLoading) {
					foreach (IMetadataFileObserver observer in this.Project.MetadataFileObservers) {
						observer.OnMetadataFileAdded(val);
					}
				}
				return base.Add(val);
			}
			else {
				return -1;
			}
		}
		private CodeGenerator CreateGenerator(MetadataFile inputFile) {
			CodeGenerator generator;
			SetTemplateBaseFolder();
			try {
				if (Package != String.Empty) {
					generator = new CodeGenerator(CodeGen.PackageLib.Package.Load(Package));
				}
				else {
					generator = new CodeGenerator(Directory.GetCurrentDirectory());
				}
			}
			finally {
				RestoreTemplateBaseFolder();
			}
			generator.Context.CurrentMetadataFile = inputFile;
			generator.Context.ProjectMetadataFiles.AddRange(this.Project.MetadataFiles);
			generator.Context.SelectedMetadataFiles.AddRange(this.SelectedMetadataFiles);
			return generator;
		}
		private void PrepareParameters(XmlDocument metadata, MetadataFile inputFile, InputParameterCollection parameters) {
			Debug.WriteLine("PrepareParameters(): Command context has " + parameters.Count + " parameters");
			for (int x = 0; x < 10; x++) {
				bool parameterChanged = false;
				foreach (InputParameter parameter in parameters) {
					if (parameter.Value.IndexOf("$") < 0 && parameter.Value.IndexOf("#") < 0) {
						continue;
					}
					//Debug.WriteLine("PrepareParameters(): Preparing parameter '" + parameter.Name + "' Value='" + parameter.Value + "'");
					Trace.Indent();
					try {
						CodeGenerator generator = CreateGenerator(inputFile);
						SetGeneratorTemplate(generator);
						generator.Template.Name = "Prepare Parameter '" + parameter.Name + "' : value '" + parameter.Value + "'";
						generator.Template.Content = new StringReader(parameter.Value);
						//generator.Template = new Template(parameter.Value, );
						//SetGeneratorTemplate(generator);
						SetCommandParameters(generator, parameters);
						//StringReader reader = ;
						//generator.Template = reader;
						StringWriter writer = new StringWriter();
						generator.UseDefaultEngine = true;
						generator.Generate(metadata, writer);
						//Trace.WriteLineIf(parameter.Value != writer.ToString(), "Prepared parameter '" + parameter.Name + "': OldVal='" + parameter.Value + "' NewVal='" + writer.ToString() + "'");
						if (parameter.Value != writer.ToString()) {
							parameter.Value = writer.ToString();
							parameterChanged = true;
						}
					}
					finally {
						Trace.Unindent();
					}
				}
				if (!parameterChanged) {
					break;
				}
			}
		}
		public void GenerateFile(MetadataFile inputFile, TextWriter outputWriter) {
			if (inputFile == null) {
				Trace.WriteLine("Running '" + Name + "' Code Generator Command");
			}
			else {
				Trace.WriteLine("Running '" + Name + "' Code Generator Command for input file '" + inputFile.Name + "'");
			}
			Trace.Indent();
			try {
				XmlDocument document = PrepareMetadata(inputFile);
				CodeGenerator generator = GetGenerator(document);
				generator.Context.CurrentMetadataFile = inputFile;
				generator.Context.SelectedMetadataFiles = this.IndividualMetadataFiles;
				generator.Generate(document, outputWriter);
				ResetGroupedMetadataCache();
			}
			finally {
				Trace.Unindent();
			}
		}
		private void Test_CodeGeneratorCommand() {
			try {
				Trace.WriteLine("Create a new project and generate using OREntity...");
				Trace.Indent();
				Project p = new Project();
				p.Save(".\\test\\output\\test_ncodegencommandproject_01.ch3");
				p.MetadataBaseDir = "..\\";
				p.TemplatePackageBaseDir = "..\\";
				p.OutputBaseDir = "..\\Output";
				MetadataFile mf = new MetadataFile(p, "UsuarioInformatica.xml");
				p.MetadataFiles.Add(mf);
				CodeGeneratorCommand gc = new CodeGeneratorCommand();
				p.GeneratorCommands.Add(gc);
				gc.IndividualMetadataFiles.Add(p.MetadataFiles[0]);
				gc.Package = "TEST_NCODEGEN_PACKAGE";
				gc.Template = "SPs_CRUD_Object";
				p.GeneratorCommands.Add(gc);
				gc.InputParameters.Add("FileNamePartial", "NCodeGen_Output_01");
				gc.OutputPath = "test_${FileNamePartial}.sql";
				p.Save();
				gc.Execute();
				// UNDONE: need to test whether files were outputted correctly

				Trace.Unindent();
			}
			catch (Exception ex) {
				Trace.WriteLine("\r\n" + ex.ToString() + "\r\n");
			}

		}
		private Entity CreateMetadataEntity(TableSchema table) {
			//string fileName = GetEntityFileName(table);
			MetadataFile file = new MetadataFile(_dataSource.Project);
			Entity entity = new Entity();
			file.MetadataEntities.Add(entity);
			file.Save(GetEntityFileName(table));
			_dataSource.Project.MetadataFiles.Add(file);
			return entity;
		}
		private void AddNewMetadataFile_Click(object sender, EventArgs e) {
			SaveFileDialog dlg = new SaveFileDialog();
			dlg.InitialDirectory = _project.GetFullMetadataPath();
			dlg.Filter = "XML Files (.XML)|*.xml|All Files (*.*)|*.*";
			if (dlg.ShowDialog(this) == DialogResult.OK)
			{
				MetadataFile file = new MetadataFile(_project);
				XmlDocument doc = new XmlDocument();
				doc.LoadXml("<Metadata></Metadata>");
				file.LoadXml(doc);
				file.Save(dlg.FileName);
				_project.MetadataFiles.Add(file);
				RefreshUI();
				OpenObjectEditor(file);
			}
		}
		void IMetadataFileObserver.OnMetadataFileRemoved(MetadataFile file) {
			if (SelectedMetadataFiles.Contains(file)) {
				SelectedMetadataFiles.Remove(file);
			}
		}
		new public void Remove(MetadataFile val) {
			if (this.Project != null && !Project.IsLoading) {
				foreach (IMetadataFileObserver observer in this.Project.MetadataFileObservers) {
					observer.OnMetadataFileRemoved(val);
				}
			}
			base.Remove(val);
		}
		new public void Insert(int index, MetadataFile val)
		{
			if (this.Project != null) {
				val.SetProject(this.Project);
			}
			if ( this.Contains(val) ) {
				base.Remove(val);
			}
			base.Insert(index, val);
		}
		new public bool Contains (MetadataFile file) {
			return ( GetMetadataFile(file.Guid) != null );
		}
		void IMetadataFileObserver.OnMetadataFileRemoved(MetadataFile file) {
			if (IndividualMetadataFiles.Contains(file)) {
				IndividualMetadataFiles.Remove(file);
			}
		}
		private XmlDocument PrepareMetadata(MetadataFile inputFile) {
			XmlDocument document = new XmlDocument();
			if (inputFile == null) {
				document.LoadXml("<" + MetadataFile.METADATA_BASE_TAG + "></" + MetadataFile.METADATA_BASE_TAG + ">");
			}
			else {
				document.LoadXml(inputFile.SaveXml());
			}
			//document.DocumentElement.InnerXml += AssembleGroupedMetadata();
			AppendGroupedMetadata(document);
			SaveMetadataTempFile(document);
//			return FilterExcludedElements(document);
			return document;
		}
		public void AutoSelectMetadataFile(MetadataFile file) {
			if (Template == String.Empty) {
				return;
			}
			CodeGenerator generator = CreateGenerator(file);
			SetGeneratorTemplate(generator);
			if (generator.Template == null)
				return;
			
			foreach (MetadataBrand brand in generator.Template.IndividualMetadataBrands) {
				foreach (IMetadataEntity entity in file.MetadataEntities) {
					if (entity.BrandName == brand.Name ||
					    (entity.BrandName == "XmlEntity" && entity.RootNodeName == brand.Name)) {
						if (!SelectedMetadataFiles.Contains(file)) {
							SelectedMetadataFiles.Add(file);
						}
					}
				}
			}

			#region GroupedMetadataBrand (DEPRECATED)

//            foreach (MetadataBrand brand in generator.Template.GroupedMetadataBrands) {
//                Debug.WriteLine("AutoSelectMetadataFile: GroupedBrand=" + brand.Name);
//                foreach (IMetadataEntity entity in file.MetadataEntities) {
//                    Debug.WriteLine("    AutoSelectMetadataFile: entity.BrandName=" + entity.BrandName + "    entity.RootNodeName=" + entity.RootNodeName);
//                    if (entity.BrandName == brand.Name ||
//                        (entity.BrandName == "XmlEntity" && entity.RootNodeName == brand.Name)) {
//                        if (!this.GroupedMetadataFiles.Contains(file)) {
//                            this.GroupedMetadataFiles.Add(file);
//                        }
//                    }
//                }
//            }

			#endregion
		}
		void IMetadataFileObserver.OnMetadataFileAdded(MetadataFile file) {
			if (AutoSelectMetadataFiles) {
				AutoSelectMetadataFile(file);
			}
		}
		private void GenerateFile(MetadataFile inputFile) {
			if (inputFile == null) {
				Trace.WriteLine("Running '" + Name + "' Code Generator Command in single file output mode.");
			}
			else {
				Trace.WriteLine("Running '" + Name + "' Code Generator Command for input file '" + inputFile.Name + "'");
			}
			Trace.Indent();
			try {
				SetOutputBaseFolder();
				try {
					AssembleGroupedMetadata();
					XmlDocument document = PrepareMetadata(inputFile);
					CodeGenerator generator = GetGenerator(document, inputFile);
					string outputPath = generator.Context.Parameters["CodeGenOutputPath"].Value;
					if (outputPath.IndexOf("${") >= 0 || outputPath.IndexOf("$!{") >= 0)
					{
						throw new CodeGenerationException(string.Format(
							"One or more expressions in the output path for the generator command '{0}' could not be evaluated for the metadata file '{1}'. The output path returned was: {2}"
							, this.Name
							, inputFile == null ? "<< No input file specified... command is running in single-output mode >>" : inputFile.Name
							, outputPath));
					}
					outputPath = Path.GetFullPath(Path.Combine(this.Project.GetFullOutputPath(), outputPath));
					generator.Context.Parameters["CodeGenOutputPath"].Value = outputPath;
					FileSystemHelper.CreateDirectory(new FileInfo(outputPath));
					Trace.WriteLine("GenerateFile(): '" + outputPath + "'");
					Trace.Indent();
					try {
						if (!Overwrite && File.Exists(outputPath)) {
							Trace.WriteLine("File exists. Existing file will not be overwritten.");
							return;
						}
						using (StringWriter stringWriter = new StringWriter()) {
							generator.Generate(document, stringWriter);
							string oldContent = "";
							if (File.Exists(outputPath))
							{
								Debug.WriteLine("Checking to see if file content has changed.");
								using (FileStream stream = new FileStream(outputPath, FileMode.Open, FileAccess.Read, FileShare.Read))
								{
									using (StreamReader reader = new StreamReader(stream))
									{
										oldContent = reader.ReadToEnd();
									}
								}
							}
							string newContent = stringWriter.ToString();
							if (newContent == oldContent && newContent != "")
							{
								Trace.WriteLine("File content has not changed. Existing file will not be overwritten.");
								return;
							}
							using (StreamWriter outputWriter = new StreamWriter(outputPath, false, _outputEncoding)) 
							{
								outputWriter.Write(newContent);
							}
						}
					}
					finally {
						Trace.Unindent();
					}
				}
				finally {
					RestoreOutputBaseFolder();
				}
			}
			finally {
				Trace.Unindent();
			}
		}
		public OREntityEditor(MetadataFile file) : this()
		{
			_MetadataFile = file;
			Enabled = true;
			Text = ToString();
		}
		public string ResolveOutputPath(MetadataFile inputFile) 
		{
			XmlDocument document = PrepareMetadata(inputFile);
			CodeGenerator generator = GetGenerator(document, inputFile);
			string outputPath = generator.Context.Parameters["CodeGenOutputPath"].Value;
			if (outputPath.IndexOf("${") >= 0 || outputPath.IndexOf("$!{") >= 0)
			{
				throw new CodeGenerationException(string.Format(
					"One or more expressions in the output path for the generator command '{0}' could not be evaluated for the metadata file '{1}'. The output path returned was: {2}"
					, this.Name
					, inputFile == null ? "<< No input file specified... command is running in single-output mode >>" : inputFile.Name
					, outputPath));
			}
			outputPath = Path.GetFullPath(Path.Combine(this.Project.GetFullOutputPath(), outputPath));

			return outputPath;
		}
		private Entity CreateMetadataFile(DataSourceEntity entity) 
		{
			MetadataFile file = new MetadataFile(this.Project);
			Entity orEntity = new Entity();
			file.MetadataEntities.Add(orEntity);
			file.Save(GetEntityFileName(entity));
			this.Project.MetadataFiles.Add(file);
			return orEntity;
		}
		public void GenerateFile(MetadataFile inputFile, TextWriter outputWriter) {
			TransformationEngineFactory.CreateEngine(_engine).ClearCache();
			if (inputFile == null) {
				Trace.WriteLine("Running '" + Name + "' Code Generator Command in single output mode.");
			}
			else {
				Trace.WriteLine("Running '" + Name + "' Code Generator Command for input file '" + inputFile.Name + "'");
			}
			Trace.Indent();
			try {
				XmlDocument document = PrepareMetadata(inputFile);
				CodeGenerator generator = GetGenerator(document, inputFile);
				generator.Generate(document, outputWriter);
				ResetGroupedMetadataCache();
			}
			finally {
				Trace.Unindent();
			}
		}
//		private void Test_MetadataFiles() {
//			try {
//				Trace.WriteLine("Create a new, non-branded metadata file and save...");
//				Trace.Indent();
//				MetadataFile f = new MetadataFile();
//				f.MetadataEntities.Add(new XmlMetadataEntity());
//				XmlMetadataEntity en = (XmlMetadataEntity) f.MetadataEntities[0];
//				en.XmlNode = (new XmlDocument()).CreateElement("Books");
//				en.XmlNode.InnerXml = "<book price=\"100.00\"/>";
//				f.Save(".\\test\\output\\test_create.xml");
//				Trace.Unindent();
//			}
//			catch (Exception ex) {
//				Trace.WriteLine("\r\n" + ex.ToString() + "\r\n");
//			}
//
//			try {
//				Trace.WriteLine("Load a non-branded metadata file and save as...");
//				Trace.Indent();
//				MetadataFile f = new MetadataFile(null, ".\\test\\output\\test_create.xml");
//				f.Save(".\\test\\output\\test_loadsaveas.xml");
//
//				// UNDONE: need to test whether files are identical
//
//				Trace.Unindent();
//			}
//			catch (Exception ex) {
//				Trace.WriteLine("\r\n" + ex.ToString() + "\r\n");
//			}
//
//			try {
//				Trace.WriteLine("Load plain XML file and save as....");
//				Trace.Indent();
//				MetadataFile f = new MetadataFile(null, ".\\test\\raw.xml");
//				f.Save(".\\test\\output\\test_rawsaveas.xml");
//
//				// UNDONE: need to test whether files are identical
//				// this can be a seperate method which takes source and dest file names
//
//				Trace.Unindent();
//			}
//			catch (Exception ex) {
//				Trace.WriteLine("\r\n" + ex.ToString() + "\r\n");
//			}
//
//
//			// Create branded metadata file and save
//
//			// Load a branded metadata file and save as
//
//			// Create mixed (branded/not branded) metadata file and save
//
//			// Load a mixed (branded/not branded) metadata file and save as
//
//		}
//

		#endregion Metadata Files

		#region Project

		private void Test_Project() {
			try {
				Trace.WriteLine("Create a new project and save...");
				Trace.Indent();
				Project p = new Project();
				p.Save(".\\test\\output\\test_projectcreate.ch3");
				p.MetadataBaseDir = "..\\";
				MetadataFile mf = new MetadataFile(p, "raw.xml");
				p.MetadataFiles.Add(mf);
				CodeGeneratorCommand gc = new CodeGeneratorCommand();
				p.GeneratorCommands.Add(gc);
				gc.IndividualMetadataFiles.Add(p.MetadataFiles[0]);
// 				gc.GroupedMetadataFiles.Add(p.MetadataFiles[0]);
				gc.Package = "CSLA";
				gc.Template = "SP_S_Object_By_Index";
				p.Save();
				Trace.Unindent();
			}
			catch (Exception ex) {
				Trace.WriteLine("\r\n" + ex.ToString() + "\r\n");
			}

			try {
				Trace.WriteLine("Load project file and save as...");
				Trace.Indent();
				Project p = Project.Load(".\\test\\output\\test_projectcreate.ch3");
				p.Save(".\\test\\output\\test_projectsaveas.ch3");

				// UNDONE: need to test whether files are identical

				Trace.Unindent();
			}
			catch (Exception ex) {
				Trace.WriteLine("\r\n" + ex.ToString() + "\r\n");
			}
		}
		private CodeGenerator GetGenerator(XmlDocument metadata, MetadataFile inputFile) {
			// FIXME: Probably need to refactor generator, package, and template code into seperate classes
			InputParameterCollection parameters = GetContextParameters();
			//Trace.WriteLine("GetGenerator(): Command context has " + parameters.Count + " parameters - " + DateTime.Now.ToString());
			PrepareParameters(metadata, inputFile, parameters);
			CodeGenerator generator = CreateGenerator(inputFile);
			SetGeneratorTemplate(generator);
			SetCommandParameters(generator, parameters);
			return generator;
		}
		private void AddNewMetadataFile_Click(object sender, EventArgs e) {
			// TODO: Add metadata file to appropriate generator commands
			MetadataFile file = new MetadataFile(_project);
			_project.MetadataFiles.Add(file);
			RefreshUI();
			IObjectEditor editor = new MetadataFileEditor();
			editor.SelectedObject = file;
			editor.SelectedObjectChanged += new EventHandler(IObjectEditor_SelectedObjectChanged);
			ObjectEditorManager.OpenObjectEditor(editor);
		}
		private void GenerateFile(MetadataFile inputFile) {
			if (inputFile == null) {
				Trace.WriteLine("Running '" + Name + "' Code Generator Command");
			}
			else {
				Trace.WriteLine("Running '" + Name + "' Code Generator Command for input file '" + inputFile.Name + "'");
			}
			Trace.Indent();
			try {
				SetOutputBaseFolder();
				try {
					XmlDocument document = PrepareMetadata(inputFile);
					CodeGenerator generator = GetGenerator(document);
					generator.Context.CurrentMetadataFile = inputFile;
					generator.Context.SelectedMetadataFiles = this.IndividualMetadataFiles;
					string outputPath = generator.Context.Parameters["CodeGenOutputPath"].Value;
					outputPath = Path.GetFullPath(Path.Combine(this.Project.GetFullOutputPath(), outputPath));
					FileSystemHelper.CreateDirectory(new FileInfo(outputPath));
					Trace.WriteLine("GenerateFile(): '" + outputPath + "'");
					Trace.Indent();
					try {
						if (!Overwrite && File.Exists(outputPath)) {
							Trace.WriteLine("File exists. Existing file will not be overwritten.");
							return;
						}
						using (StringWriter stringWriter = new StringWriter()) {
							generator.Generate(document, stringWriter);
							using (StreamWriter outputWriter = new StreamWriter(outputPath)) 
							{
								outputWriter.Write(stringWriter.ToString());
							}
						}
					}
					finally {
						Trace.Unindent();
					}
				}
				finally {
					RestoreOutputBaseFolder();
				}
			}
			finally {
				Trace.Unindent();
			}
		}