context: //
  // DO NOT REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  //
  // @Authors:
  //       timop
  //
  // Copyright 2004-2013 by OM International
  //
  // This file is part of OpenPetra.org.
  //
  // OpenPetra.org is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // OpenPetra.org is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with OpenPetra.org.  If not, see <http://www.gnu.org/licenses/>.
  //
  using System;
  using System.IO;
  using System.Xml;
  using System.Collections;
  using System.Collections.Specialized;
  using System.Collections.Generic;
  using Ict.Common.IO;
  using Ict.Common;
  using Ict.Tools.DBXML;
  
  namespace Ict.Tools.CodeGeneration
  {
      /// This class represents the code of a windows form in memory
      /// There are other classes that fill this model by reading from the Designer.cs file or the yaml file
      /// There are other classes that will write the code
      ///
      /// each xml element is directly linked in the FXmlNodes list, no matter which depth it is in the actual xml structure
      /// each control (menu, gui controls, etc) is linked in the FControlList
      /// all changes are done to the xml structure as well as to the FControlList and the FXmlNodes
      /// this allows easy saving of the modified xml
      public class TCodeStorage
      {
          /// contains all controls, ie also menus etc; this is a sorted list for easily finding values, but also keep them ordered
          public Dictionary <string, TControlDef>FControlList = new Dictionary <string, TControlDef>();
  
          /// it seems, on Mono the Dictionary gets sorted differently, therefore it is not useful for getting the RootControl etc; so we use a specific SortedList for this
          public SortedList <int, TControlDef>FSortedControlList = new SortedList <int, TControlDef>();
  
          /// <summary>
          /// list of event handlers
          /// </summary>
          public Dictionary <string, TEventHandler>FEventList = new Dictionary <string, TEventHandler>();
  
          /// <summary>
          /// list of action handlers
          /// </summary>
          public Dictionary <string, TActionHandler>FActionList = new Dictionary <string, TActionHandler>();
  
          /// <summary>
          /// list of report parameters
          /// </summary>
          public Dictionary <string, TReportParameter>FReportParameterList = new Dictionary <string, TReportParameter>();
  
          /// <summary>class to inherit from</summary>
          public string FBaseClass = "";
          /// <summary>interface to be inherited</summary>
          public string FInterfaceName = "";
          /// <summary>the type of UtilObject, eg. for edit window or other type of window</summary>
          public string FUtilObjectClass = "";
          /// <summary>the class for the generated file</summary>
          public string FClassName = "";
          /// <summary>the title for the form</summary>
          public string FFormTitle = "";
          /// <summary>the namespace for the generated file</summary>
          public string FNamespace = "";
          /// <summary>the name of the yaml file</summary>
          public string FFilename = "";
          /// <summary>the name of the manualcode file</summary>
          public string FManualCodeFilename = "";
          /// <summary>store the code for installing the handlers in this variable</summary>
          public string FEventHandler = "";
          /// <summary>store code in this variable for the event handlers</summary>
          public string FEventHandlersImplementation = "";
          /// <summary>store the code for the action handlers in this variable</summary>
          public string FActionHandlers = "";
          /// <summary>store code in this variable for the report parameters</summary>
          public string FReportParametersImplementation = "";
          /// <summary>height of the generate window</summary>
          public Int32 FHeight = 500;
          /// <summary>width of the generate window</summary>
          public Int32 FWidth = 700;
          /// <summary>list of variables that will be inserted into the template code</summary>
          public XmlNode FTemplateParameters = null;
          /// <summary>the xml representation of the yaml file</summary>
          public XmlDocument FXmlDocument = null;
          /// <summary>all xml nodes of the yaml file</summary>
          public SortedList FXmlNodes = null;
          /// <summary>the root xml node of the yaml file</summary>
          public XmlNode FRootNode = null;
  
          private string FManualCodeFileContent = "";
  
          private const string STOCK_NEW_RECORD_IMAGE = "New_Record.ico";
          private const string STOCK_DELETE_RECORD_IMAGE = "Delete_Record.ico";
  
          /// <summary>constructor</summary>
          public TCodeStorage(XmlDocument AXmlDocument, SortedList AXmlNodes)
          {
              FXmlDocument = AXmlDocument;
              FXmlNodes = AXmlNodes;
          }
  
          /// <summary>
          /// set the path to the file containing manual code for the form;
          /// insert calls to manual functions which would not be called if they do not exist
          /// </summary>
          public string ManualCodeFilename
          {
              set
              {
                  FManualCodeFilename = value;
              }
          }
  
          /// <summary>
          /// check if the text is in the manual code file for the file that is about to be generated
          /// </summary>
          /// <param name="ASearchText"></param>
          /// <returns></returns>
          public bool ManualFileExistsAndContains(string ASearchText)
          {
              if ((FManualCodeFilename.Length > 0) && (FManualCodeFileContent.Length == 0) && System.IO.File.Exists(FManualCodeFilename))
              {
                  System.IO.StreamReader r = new System.IO.StreamReader(FManualCodeFilename);
                  FManualCodeFileContent = r.ReadToEnd();
                  r.Close();
              }
  
              return FManualCodeFileContent.Contains(ASearchText);
          }
  
          /// <summary>
          /// check if main or ManualCode file contains the search text
          /// </summary>
          /// <param name="ANamespaceAndClassname">only works for files in the same directory at the moment</param>
          /// <param name="ASearchText"></param>
          /// <returns></returns>
          public bool ImplementationContains(string ANamespaceAndClassname, string ASearchText)
          {
              string pathAndName = System.IO.Path.GetDirectoryName(Path.GetFullPath(this.FFilename)).Replace("\\", "/");
  
              // cut off after /Client/lib
              pathAndName = pathAndName.Substring(0, pathAndName.IndexOf("ICT/Petra/Client/") + "ICT/Petra/Client".Length);
  
              // use only last part of namespace after Ict.Petra.Client
              ANamespaceAndClassname = ANamespaceAndClassname.Substring("Ict.Petra.Client".Length);
              pathAndName += ANamespaceAndClassname.Substring(0, ANamespaceAndClassname.LastIndexOf(".")).Replace(".", "/");
  
              // get the file name without TFrm prefix
              string filename = "/" + ANamespaceAndClassname.Substring(ANamespaceAndClassname.LastIndexOf(".") + 1 + 4);
              string alternativeFileName = filename;
  
              if (!System.IO.File.Exists(pathAndName + filename + ".cs"))
              {
                  filename += "-generated";
              }
  
              if (System.IO.File.Exists(pathAndName + filename + ".cs"))
              {
                  System.IO.StreamReader r = new System.IO.StreamReader(pathAndName + filename + ".cs");
                  string temp = r.ReadToEnd();
                  r.Close();
  
                  if (temp.Contains(ASearchText))
                  {
                      return true;
                  }
              }
              else
              {
                  Console.WriteLine("Warning naming conventions: cannot find file " +
                      pathAndName + filename + ".cs or " +
                      pathAndName + alternativeFileName + ".cs");
              }
  
              string ManualCodeFile = pathAndName + filename + ".ManualCode.cs";
  
              if (!System.IO.File.Exists(ManualCodeFile))
              {
                  ManualCodeFile = ManualCodeFile.Replace("-generated.cs", ".ManualCode.cs");
              }
  
              if (System.IO.File.Exists(ManualCodeFile))
              {
                  System.IO.StreamReader r = new System.IO.StreamReader(ManualCodeFile);
                  string temp = r.ReadToEnd();
                  r.Close();
  
                  if (temp.Contains(ASearchText))
                  {
                      return true;
                  }
              }
  
              return false;
          }
  
          /// <summary>
          /// returns a list of controls that are not used anywhere on the screen
          /// </summary>
          /// <returns></returns>
          public List <TControlDef>GetOrphanedControls()
          {
              List <TControlDef>result = new List <TControlDef>();
  
              foreach (TControlDef ctrl in FSortedControlList.Values)
              {
                  if ((ctrl.parentName == null) || (ctrl.parentName.Length == 0))
                  {
                      if (ctrl.HasAttribute("RootControl") && (ctrl.GetAttribute("RootControl").ToLower() == "true"))
                      {
                          // a root control has no parent by definition
                      }
                      else if ((GetRootControl("content", false) == ctrl) || (GetRootControl("mnu", false) == ctrl)
                               || (GetRootControl("tbr", false) == ctrl) || (GetRootControl("stb", false) == ctrl))
                      {
                          // root control has no parent
                      }
                      else if (!ctrl.controlName.StartsWith("Empty"))
                      {
                          result.Add(ctrl);
                      }
                  }
              }
  
              return result;
          }
  
          /// <summary>
          /// get a control from the list of controls defined in the yaml file
          /// </summary>
          /// <param name="AControlName"></param>
          /// <returns></returns>
          public TControlDef GetControl(string AControlName)
          {
              if (FControlList.ContainsKey(AControlName))
              {
                  return (TControlDef)FControlList[AControlName];
              }
  
              return null;
          }
  
          /// <summary>
          /// get the main menustrip, tabpage, statusstrip etc;
          /// if prefix is content, the first available pnl, uco, tpg or grp control is returned;
          /// the first control can be overwritten with attribute RootControl=true; this is necessary for the reports, see tabReportSettings
          /// </summary>
          /// <param name="APrefix">can be mnu, tab, tbr, sbt, stb, content</param>
          /// <param name="AThrowException">if there is no root control, throw an exception</param>
          /// <returns></returns>
          public TControlDef GetRootControl(string APrefix, bool AThrowException)
          {
              TControlDef firstControl = null;
  
              foreach (TControlDef ctrl in FSortedControlList.Values)
              {
  
gt:                 if (ctrl.controlTypePrefix == APrefix)