PsetDefinition Process(string schemaVersion, FileInfo PSDfileName)
        {
            PsetDefinition pset = new PsetDefinition();
            XDocument      doc  = XDocument.Load(PSDfileName.FullName);

            // Older versions of psd uses namespace!
            var        nsInfo = doc.Root.Attributes("xmlns").FirstOrDefault();
            XNamespace ns     = "";

            if (nsInfo != null)
            {
                ns = nsInfo.Value;
            }

            pset.Name       = doc.Elements(ns + "PropertySetDef").Elements(ns + "Name").FirstOrDefault().Value;
            pset.IfcVersion = doc.Elements(ns + "PropertySetDef").Elements(ns + "IfcVersion").FirstOrDefault().Attribute("version").Value.Replace(" ", "");
            if (pset.IfcVersion.StartsWith("2"))
            {
                if (pset.IfcVersion.Equals("2X", StringComparison.CurrentCultureIgnoreCase))
                {
                    pset.IfcVersion = "IFC" + pset.IfcVersion.ToUpper() + "2"; // BUG in the documentation. It ony contains "2x" instead of "2x2"
                }
                else
                {
                    pset.IfcVersion = "IFC" + pset.IfcVersion.ToUpper(); // Namespace cannot start with a number. e.g. make sure 2x3 -> IFC2x3
                }
            }
            else if (pset.IfcVersion.StartsWith("IFC4"))
            {
                pset.IfcVersion = schemaVersion.ToUpper();
            }

            if (doc.Element(ns + "PropertySetDef").Attribute("ifdguid") != null)
            {
                pset.IfdGuid = doc.Element(ns + "PropertySetDef").Attribute("ifdguid").Value;
            }
            // Get applicable classes
            IEnumerable <XElement> applicableClasses = from el in doc.Descendants(ns + "ClassName") select el;
            IList <string>         applClassesList   = new List <string>();

            foreach (XElement applClass in applicableClasses)
            {
                string className = ProcessPsetDefinition.removeInvalidNName(applClass.Value);
                if (!string.IsNullOrEmpty(className))
                {
                    applClassesList.Add(className);
                }
            }

            pset.ApplicableClasses = applClassesList;

            XElement applType = doc.Elements(ns + "PropertySetDef").Elements(ns + "ApplicableTypeValue").FirstOrDefault();

            if (applType != null)
            {
                string applicableType = applType.Value;
                if (!string.IsNullOrEmpty(applicableType) && !applicableType.Equals("N/A", StringComparison.InvariantCultureIgnoreCase))
                {
                    // Remove "SELF\" in the applicable type
                    if (applicableType.Contains("SELF\\"))
                    {
                        applicableType = applicableType.Replace("SELF\\", "");
                    }

                    string[] applTypeStr = applicableType.Split('/', '.', '=');
                    pset.ApplicableType = applTypeStr[0];
                    if (applTypeStr.Count() > 1)
                    {
                        pset.PredefinedType = applTypeStr[applTypeStr.Count() - 1].Replace("\"", "");
                    }

                    // If the applicable type contains more than 1 entry, add them into the applicable classes
                    string[] addClasses = pset.ApplicableType.Split(',');
                    if (addClasses.Count() > 1)
                    {
                        foreach (string addClass in addClasses)
                        {
                            string addClassTr = addClass.TrimStart().TrimEnd();
                            if (!pset.ApplicableClasses.Contains(addClassTr))
                            {
                                pset.ApplicableClasses.Add(addClassTr);
                            }
                        }
                    }
                }
            }

            IList <PsetProperty> propList = new List <PsetProperty>();
            var pDefs = from p in doc.Descendants(ns + "PropertyDef") select p;

            foreach (XElement pDef in pDefs)
            {
                PsetProperty       prop  = getPropertyDef(ns, pDef);
                SharedParameterDef shPar = new SharedParameterDef();
                if (prop == null)
                {
#if DEBUG
                    logF.WriteLine("%Error: Mising PropertyType data for {0}.{1}", pset.Name, pDef.Element(ns + "Name").Value);
#endif
                }
                else
                {
                    propList.Add(prop);
                }
            }
            pset.properties = propList;

            return(pset);
        }
        public PsetProperty getPropertyDef(XNamespace ns, XElement pDef)
        {
            PsetProperty prop = new PsetProperty();

            if (pDef.Attribute("ifdguid") != null)
            {
                prop.IfdGuid = pDef.Attribute("ifdguid").Value;
            }
            prop.Name = pDef.Element(ns + "Name").Value;
            IList <NameAlias> aliases      = new List <NameAlias>();
            XElement          nAliasesElem = pDef.Elements(ns + "NameAliases").FirstOrDefault();

            if (nAliasesElem != null)
            {
                var nAliases = from el in nAliasesElem.Elements(ns + "NameAlias") select el;
                foreach (XElement alias in nAliases)
                {
                    NameAlias nameAlias = new NameAlias();
                    nameAlias.Alias = alias.Value;
                    nameAlias.lang  = alias.Attribute("lang").Value;
                    aliases.Add(nameAlias);
                }
            }
            if (aliases.Count > 0)
            {
                prop.NameAliases = aliases;
            }

            PropertyDataType dataTyp = null;
            var      propType        = pDef.Elements(ns + "PropertyType").FirstOrDefault();
            XElement propDetType     = propType.Elements().FirstOrDefault();

            if (propDetType == null)
            {
#if DEBUG
                logF.WriteLine("%Warning: Missing PropertyType for {0}.{1}", pDef.Parent.Parent.Element(ns + "Name").Value, prop.Name);
#endif
                return(prop);
            }

            if (propDetType.Name.LocalName.Equals("TypePropertySingleValue"))
            {
                XElement            dataType = propDetType.Element(ns + "DataType");
                PropertySingleValue sv       = new PropertySingleValue();
                if (dataType.Attribute("type") != null)
                {
                    sv.DataType = dataType.Attribute("type").Value;
                }
                else
                {
                    sv.DataType = "IfcLabel"; // Set this to default if missing
#if DEBUG
                    logF.WriteLine("%Warning: Missing TypePropertySingleValue for {0}.{1}", pDef.Parent.Parent.Element(ns + "Name").Value, prop.Name);
#endif
                }
                dataTyp = sv;
            }
            else if (propDetType.Name.LocalName.Equals("TypePropertyReferenceValue"))
            {
                PropertyReferenceValue rv = new PropertyReferenceValue();
                // Older versions uses Element DataType!
                XElement dt = propDetType.Element(ns + "DataType");
                if (dt == null)
                {
                    rv.RefEntity = propDetType.Attribute("reftype").Value;
                }
                else
                {
                    rv.RefEntity = dt.Attribute("type").Value;
                }
                dataTyp = rv;
            }
            else if (propDetType.Name.LocalName.Equals("TypePropertyEnumeratedValue"))
            {
                PropertyEnumeratedValue pev = new PropertyEnumeratedValue();
                var enumItems = propDetType.Descendants(ns + "EnumItem");
                if (enumItems.Count() > 0)
                {
                    pev.Name    = propDetType.Element(ns + "EnumList").Attribute("name").Value;
                    pev.EnumDef = new List <PropertyEnumItem>();
                    foreach (var en in enumItems)
                    {
                        string enumItemName            = en.Value.ToString();
                        IEnumerable <XElement> consDef = null;
                        if (propDetType.Element(ns + "ConstantList") != null)
                        {
                            consDef = from el in propDetType.Element(ns + "ConstantList").Elements(ns + "ConstantDef")
                                      where (el.Element(ns + "Name").Value.Equals(enumItemName, StringComparison.CurrentCultureIgnoreCase))
                                      select el;
                        }

                        if (propDetType.Element(ns + "ConstantList") != null)
                        {
                            var consList = propDetType.Element(ns + "ConstantList").Elements(ns + "ConstantDef");
                            if (consList != null && consList.Count() != enumItems.Count())
                            {
#if DEBUG
                                logF.WriteLine("%Warning: EnumList (" + enumItems.Count().ToString() + ") is not consistent with the ConstantList ("
                                               + consList.Count().ToString() + ") for: {0}.{1}",
                                               pDef.Parent.Parent.Element(ns + "Name").Value, prop.Name);
#endif
                            }
                        }

                        if (consDef != null && consDef.Count() > 0)
                        {
                            foreach (var cD in consDef)
                            {
                                PropertyEnumItem enumItem = new PropertyEnumItem();
                                enumItem.EnumItem = cD.Elements(ns + "Name").FirstOrDefault().Value;
                                enumItem.Aliases  = new List <NameAlias>();
                                var eAliases = from el in cD.Elements(ns + "NameAliases").FirstOrDefault().Elements(ns + "NameAlias") select el;
                                if (eAliases.Count() > 0)
                                {
                                    foreach (var aliasItem in eAliases)
                                    {
                                        NameAlias nal = new NameAlias();
                                        nal.Alias = aliasItem.Value;
                                        nal.lang  = aliasItem.Attribute("lang").Value;
                                        enumItem.Aliases.Add(nal);
                                    }
                                }
                                pev.EnumDef.Add(enumItem);
                            }
                        }
                        else
                        {
                            PropertyEnumItem enumItem = new PropertyEnumItem();
                            enumItem.EnumItem = enumItemName;
                            enumItem.Aliases  = new List <NameAlias>();
                            pev.EnumDef.Add(enumItem);
                        }
                    }
                }
                else
                {
                    {
#if DEBUG
                        logF.WriteLine("%Warning: EnumList {0}.{1} is empty!", pDef.Parent.Parent.Element(ns + "Name").Value, prop.Name);
#endif
                    }
                    // If EnumList is empty, try to see whether ConstantDef has values. The Enum item name will be taken from the ConstantDef.Name
                    pev.Name    = "PEnum_" + prop.Name;
                    pev.EnumDef = new List <PropertyEnumItem>();
                    var consDef = from el in propDetType.Element(ns + "ConstantList").Elements(ns + "ConstantDef")
                                  select el;
                    if (consDef != null && consDef.Count() > 0)
                    {
                        foreach (var cD in consDef)
                        {
                            PropertyEnumItem enumItem = new PropertyEnumItem();
                            enumItem.EnumItem = cD.Elements(ns + "Name").FirstOrDefault().Value;
                            enumItem.Aliases  = new List <NameAlias>();
                            var eAliases = from el in cD.Elements(ns + "NameAliases").FirstOrDefault().Elements(ns + "NameAlias") select el;
                            if (eAliases.Count() > 0)
                            {
                                foreach (var aliasItem in eAliases)
                                {
                                    NameAlias nal = new NameAlias();
                                    nal.Alias = aliasItem.Value;
                                    nal.lang  = aliasItem.Attribute("lang").Value;
                                    enumItem.Aliases.Add(nal);
                                }
                            }
                            pev.EnumDef.Add(enumItem);
                        }
                    }
                }
                dataTyp = pev;
            }
            else if (propDetType.Name.LocalName.Equals("TypePropertyBoundedValue"))
            {
                XElement             dataType = propDetType.Element(ns + "DataType");
                PropertyBoundedValue bv       = new PropertyBoundedValue();
                bv.DataType = dataType.Attribute("type").Value;
                dataTyp     = bv;
            }
            else if (propDetType.Name.LocalName.Equals("TypePropertyListValue"))
            {
                XElement          dataType = propDetType.Descendants(ns + "DataType").FirstOrDefault();
                PropertyListValue lv       = new PropertyListValue();
                lv.DataType = dataType.Attribute("type").Value;
                dataTyp     = lv;
            }
            else if (propDetType.Name.LocalName.Equals("TypePropertyTableValue"))
            {
                PropertyTableValue tv = new PropertyTableValue();
                var tve = propDetType.Element(ns + "Expression");
                if (tve != null)
                {
                    tv.Expression = tve.Value;
                }
                XElement el = propDetType.Element(ns + "DefiningValue");
                if (el != null)
                {
                    XElement el2 = propDetType.Element(ns + "DefiningValue").Element(ns + "DataType");
                    if (el2 != null)
                    {
                        tv.DefiningValueType = el2.Attribute("type").Value;
                    }
                }
                el = propDetType.Element(ns + "DefinedValue");
                if (el != null)
                {
                    XElement el2 = propDetType.Element(ns + "DefinedValue").Element(ns + "DataType");
                    if (el2 != null)
                    {
                        tv.DefinedValueType = el2.Attribute("type").Value;
                    }
                }
                dataTyp = tv;
            }
            else if (propDetType.Name.LocalName.Equals("TypeComplexProperty"))
            {
                ComplexProperty compProp = new ComplexProperty();
                compProp.Name       = propDetType.Attribute("name").Value;
                compProp.Properties = new List <PsetProperty>();
                foreach (XElement cpPropDef in propDetType.Elements(ns + "PropertyDef"))
                {
                    PsetProperty pr = getPropertyDef(ns, cpPropDef);
                    if (pr == null)
                    {
#if DEBUG
                        logF.WriteLine("%Error: Mising PropertyType data in complex property {0}.{1}.{2}", propDetType.Parent.Parent.Element(ns + "Name").Value,
                                       prop.Name, cpPropDef.Element(ns + "Name").Value);
#endif
                    }
                    else
                    {
                        compProp.Properties.Add(pr);
                    }
                }
                dataTyp = compProp;
            }
            prop.PropertyType = dataTyp;

            return(prop);
        }
        void processSimpleProperty(StreamWriter outF, PsetProperty prop, string propNamePrefix, string IfcVersion, string schemaVersion, string varName)
        {
            // For now, keep the same approach for naming the properties (i.e. without prefix)
            //outF.WriteLine("\t\t\t\tifcPSE = new PropertySetEntry(\"{0}.{1}\");", propNamePrefix, prop.Name);
            outF.WriteLine("\t\t\t\tifcPSE = new PropertySetEntry(\"{0}\");", prop.Name);
            outF.WriteLine("\t\t\t\tifcPSE.PropertyName = \"{0}\";", prop.Name);
            if (prop.PropertyType != null)
            {
                if (prop.PropertyType is PropertyEnumeratedValue)
                {
                    PropertyEnumeratedValue propEnum = prop.PropertyType as PropertyEnumeratedValue;
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.Label;");
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyValueType = PropertyValueType.EnumeratedValue;");
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyEnumerationType = typeof(Revit.IFC.Export.Exporter.PropertySet." + IfcVersion + "." + propEnum.Name + ");");
                    IList <string> enumItems = new List <string>();
                    foreach (PropertyEnumItem enumItem in propEnum.EnumDef)
                    {
                        string item = HandleInvalidCharacter(enumItem.EnumItem);
                        enumItems.Add(item);
                    }
                    writeEnumFile(IfcVersion, schemaVersion, propEnum.Name, enumItems);
                }
                else if (prop.PropertyType is PropertyReferenceValue)
                {
                    PropertyReferenceValue propRef = prop.PropertyType as PropertyReferenceValue;
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.{0};", propRef.RefEntity.Trim());
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyValueType = PropertyValueType.ReferenceValue;");
                }
                else if (prop.PropertyType is PropertyListValue)
                {
                    PropertyListValue propList = prop.PropertyType as PropertyListValue;
                    if (propList.DataType != null)
                    {
                        outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.{0};", propList.DataType.ToString().Replace("Ifc", "").Replace("Measure", "").Trim());
                    }
                    else
                    {
                        outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.Label;"); // default to Label if not defined
                    }
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyValueType = PropertyValueType.ListValue;");
                }
                else if (prop.PropertyType is PropertyTableValue)
                {
                    PropertyTableValue propTab = prop.PropertyType as PropertyTableValue;
                    // TableValue has 2 types: DefiningValue and DefinedValue. This is not fully implemented yet
                    if (propTab.DefinedValueType != null)
                    {
                        outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.{0};", propTab.DefinedValueType.ToString().Replace("Ifc", "").Replace("Measure", "").Trim());
                    }
                    else
                    {
                        outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.Label;"); // default to Label if missing
                    }
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyValueType = PropertyValueType.TableValue;");
                }
                else
                {
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.{0};", prop.PropertyType.ToString().Replace("Ifc", "").Replace("Measure", "").Trim());
                }
            }

            if (prop.NameAliases != null)
            {
                foreach (NameAlias alias in prop.NameAliases)
                {
                    LanguageType lang = checkAliasLanguage(alias.lang);
                    outF.WriteLine("\t\t\t\tifcPSE.AddLocalizedParameterName(LanguageType.{0}, \"{1}\");", lang, alias.Alias);
                }
            }

            string calcName = "Revit.IFC.Export.Exporter.PropertySet.Calculators." + prop.Name + "Calculator";

            outF.WriteLine("\t\t\t\tcalcType = System.Reflection.Assembly.GetExecutingAssembly().GetType(\"" + calcName + "\");");
            outF.WriteLine("\t\t\t\tif (calcType != null)");
            outF.WriteLine("\t\t\t\t\tifcPSE.PropertyCalculator = (PropertyCalculator) calcType.GetConstructor(Type.EmptyTypes).Invoke(new object[]{});");
            outF.WriteLine("\t\t\t\t{0}.AddEntry(ifcPSE);", varName);
            outF.WriteLine("");
        }
        public void processSimpleProperty(StreamWriter outF, PsetProperty prop, string propNamePrefix, string IfcVersion, string schemaVersion,
                                          string varName, VersionSpecificPropertyDef vSpecPDef, string outputFile)
        {
            outF.WriteLine("\t\t\t\tifcPSE = new PropertySetEntry(\"{0}\");", prop.Name);
            outF.WriteLine("\t\t\t\tifcPSE.PropertyName = \"{0}\";", prop.Name);
            if (prop.PropertyType != null)
            {
                if (prop.PropertyType is PropertyEnumeratedValue)
                {
                    PropertyEnumeratedValue propEnum = prop.PropertyType as PropertyEnumeratedValue;
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.Label;");
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyValueType = PropertyValueType.EnumeratedValue;");
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyEnumerationType = typeof(Revit.IFC.Export.Exporter.PropertySet." + IfcVersion + "." + propEnum.Name + ");");
                    IList <string> enumItems = new List <string>();
                    foreach (PropertyEnumItem enumItem in propEnum.EnumDef)
                    {
                        string item = HandleInvalidCharacter(enumItem.EnumItem);
                        enumItems.Add(item);
                    }
                    writeEnumFile(IfcVersion, schemaVersion, propEnum.Name, enumItems, outputFile);
                }
                else if (prop.PropertyType is PropertyReferenceValue)
                {
                    PropertyReferenceValue propRef = prop.PropertyType as PropertyReferenceValue;
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.{0};", propRef.RefEntity.Trim());
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyValueType = PropertyValueType.ReferenceValue;");
                }
                else if (prop.PropertyType is PropertyListValue)
                {
                    PropertyListValue propList = prop.PropertyType as PropertyListValue;
                    if (propList.DataType != null && !propList.DataType.Equals("IfcValue", StringComparison.InvariantCultureIgnoreCase))
                    {
                        outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.{0};", propList.DataType.ToString().Replace("Ifc", "").Replace("Measure", "").Trim());
                    }
                    else
                    {
                        outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.Label;"); // default to Label if not defined
                    }
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyValueType = PropertyValueType.ListValue;");
                }
                else if (prop.PropertyType is PropertyTableValue)
                {
                    PropertyTableValue propTab = prop.PropertyType as PropertyTableValue;
                    // TableValue has 2 types: DefiningValue and DefinedValue. This is not fully implemented yet
                    if (propTab.DefinedValueType != null)
                    {
                        outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.{0};", propTab.DefinedValueType.ToString().Replace("Ifc", "").Replace("Measure", "").Trim());
                    }
                    else
                    {
                        outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.Label;"); // default to Label if missing
                    }
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyValueType = PropertyValueType.TableValue;");
                }
                else
                {
                    outF.WriteLine("\t\t\t\tifcPSE.PropertyType = PropertyType.{0};", prop.PropertyType.ToString().Replace("Ifc", "").Replace("Measure", "").Trim());
                }
            }
            else
            {
                prop.PropertyType = new PropertySingleValue();
                // Handle bad cases where datatype is somehow missing in the PSD
                if (prop.Name.ToLowerInvariant().Contains("ratio") ||
                    prop.Name.ToLowerInvariant().Contains("length") ||
                    prop.Name.ToLowerInvariant().Contains("width") ||
                    prop.Name.ToLowerInvariant().Contains("thickness") ||
                    prop.Name.ToLowerInvariant().Contains("angle") ||
                    prop.Name.ToLowerInvariant().Contains("transmittance") ||
                    prop.Name.ToLowerInvariant().Contains("fraction") ||
                    prop.Name.ToLowerInvariant().Contains("rate") ||
                    prop.Name.ToLowerInvariant().Contains("velocity") ||
                    prop.Name.ToLowerInvariant().Contains("speed") ||
                    prop.Name.ToLowerInvariant().Contains("capacity") ||
                    prop.Name.ToLowerInvariant().Contains("pressure") ||
                    prop.Name.ToLowerInvariant().Contains("temperature") ||
                    prop.Name.ToLowerInvariant().Contains("power") ||
                    prop.Name.ToLowerInvariant().Contains("heatgain") ||
                    prop.Name.ToLowerInvariant().Contains("efficiency") ||
                    prop.Name.ToLowerInvariant().Contains("resistance") ||
                    prop.Name.ToLowerInvariant().Contains("coefficient") ||
                    prop.Name.ToLowerInvariant().Contains("measure"))
                {
                    (prop.PropertyType as PropertySingleValue).DataType = "IfcReal";
                }
                else if (prop.Name.ToLowerInvariant().Contains("loadbearing"))
                {
                    (prop.PropertyType as PropertySingleValue).DataType = "IfcBoolean";
                }
                else
                {
                    (prop.PropertyType as PropertySingleValue).DataType = "IfcLabel";
                }
#if DEBUG
                logF.WriteLine("%Warning: " + prop.Name + " from " + vSpecPDef.PropertySetDef.Name + "(" + vSpecPDef.SchemaFileVersion + ") is missing PropertyType/datatype. Set to default "
                               + (prop.PropertyType as PropertySingleValue).DataType);
#endif
            }

            // Append new definition to the Shared parameter file
            SharedParameterDef newPar = new SharedParameterDef();
            newPar.Name = prop.Name;

            // Use IfdGuid for the GUID if defined
            Guid pGuid      = Guid.Empty;
            bool hasIfdGuid = false;
            if (!string.IsNullOrEmpty(prop.IfdGuid))
            {
                if (Guid.TryParse(prop.IfdGuid, out pGuid))
                {
                    hasIfdGuid = true;
                }
            }
            if (pGuid == Guid.Empty)
            {
                pGuid = Guid.NewGuid();
            }

            newPar.ParamGuid = pGuid;

            if (prop.PropertyType != null)
            {
                newPar.Description = prop.PropertyType.ToString().Split(' ', '\t')[0].Trim(); // Put the original IFC datatype in the description
            }
            else
            {
#if DEBUG
                logF.WriteLine("%Warning: " + prop.Name + " from " + vSpecPDef.PropertySetDef.Name + "(" + vSpecPDef.SchemaFileVersion + ") is missing PropertyType/datatype.");
#endif
            }

            if (prop.PropertyType is PropertyEnumeratedValue)
            {
                newPar.ParamType = "TEXT"; // Support only a single enum value (which is most if not all cases known)
            }
            else if (prop.PropertyType is PropertyReferenceValue ||
                     prop.PropertyType is PropertyBoundedValue ||
                     prop.PropertyType is PropertyListValue ||
                     prop.PropertyType is PropertyTableValue)
            {
                // For all the non-simple value, a TEXT parameter will be created that will contain formatted string
                newPar.ParamType = "MULTILINETEXT";
                if (prop.PropertyType is PropertyBoundedValue)
                {
                    newPar.Description = "PropertyBoundedValue"; // override the default to the type of property datatype
                }
                else if (prop.PropertyType is PropertyListValue)
                {
                    newPar.Description = "PropertyListValue"; // override the default to the type of property datatype
                }
                else if (prop.PropertyType is PropertyTableValue)
                {
                    newPar.Description = "PropertyTableValue"; // override the default to the type of property datatype
                }
            }
            else if (prop.PropertyType is PropertySingleValue)
            {
                PropertySingleValue propSingle = prop.PropertyType as PropertySingleValue;
                newPar.Description = propSingle.DataType; // Put the original IFC datatype in the description

                if (propSingle.DataType.Equals("IfcPositivePlaneAngleMeasure", StringComparison.InvariantCultureIgnoreCase) ||
                    propSingle.DataType.Equals("IfcSolidAngleMeasure", StringComparison.InvariantCultureIgnoreCase))
                {
                    newPar.ParamType = "ANGLE";
                }
                else if (propSingle.DataType.Equals("IfcAreaMeasure", StringComparison.InvariantCultureIgnoreCase))
                {
                    newPar.ParamType = "AREA";
                }
                else if (propSingle.DataType.Equals("IfcMonetaryMeasure", StringComparison.InvariantCultureIgnoreCase))
                {
                    newPar.ParamType = "CURRENCY";
                }
                else if (propSingle.DataType.Equals("IfcPositivePlaneAngleMeasure", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcCardinalPointReference", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcCountMeasure", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcDayInMonthNumber", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcDayInWeekNumber", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcDimensionCount", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcInteger", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcIntegerCountRateMeasure", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcMonthInYearNumber", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcTimeStamp", StringComparison.InvariantCultureIgnoreCase))
                {
                    newPar.ParamType = "INTEGER";
                }
                else if (propSingle.DataType.Equals("IfcLengthMeasure", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcNonNegativeLengthMeasure", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcPositiveLengthMeasure", StringComparison.InvariantCultureIgnoreCase))
                {
                    newPar.ParamType = "LENGTH";
                }
                else if (propSingle.DataType.Equals("IfcMassDensityMeasure", StringComparison.InvariantCultureIgnoreCase))
                {
                    newPar.ParamType = "MASS_DENSITY";
                }
                else if (propSingle.DataType.Equals("IfcArcIndex", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcComplexNumber", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcCompoundPlaneAngleMeasure", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcLineIndex", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcPropertySetDefinitionSet", StringComparison.InvariantCultureIgnoreCase))
                {
                    newPar.ParamType = "MULTILINETEXT";
                }
                else if (propSingle.DataType.Equals("IfcBinary", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcBoxAlignment", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcDate", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcDateTime", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcDescriptiveMeasure", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcDuration", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcFontStyle", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcFontVariant", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcFontWeight", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcGloballyUniqueId", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcIdentifier", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcLabel", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcLanguageId", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcPresentableText", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcText", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcTextAlignment", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcTextDecoration", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcTextFontName", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcTextTransformation", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcTime", StringComparison.InvariantCultureIgnoreCase))
                {
                    newPar.ParamType = "TEXT";
                }
                else if (propSingle.DataType.Equals("IfcURIReference", StringComparison.InvariantCultureIgnoreCase))
                {
                    newPar.ParamType = "URL";
                }
                else if (propSingle.DataType.Equals("IfcVolumeMeasure", StringComparison.InvariantCultureIgnoreCase))
                {
                    newPar.ParamType = "VOLUME";
                }
                else if (propSingle.DataType.Equals("IfcBoolean", StringComparison.InvariantCultureIgnoreCase) ||
                         propSingle.DataType.Equals("IfcLogical", StringComparison.InvariantCultureIgnoreCase))
                {
                    newPar.ParamType = "YESNO";
                }
                else
                {
                    newPar.ParamType = "NUMBER";
                }
            }

            if (!SharedParamFileDict.ContainsKey(newPar.Name))
            {
                SharedParamFileDict.Add(newPar.Name, newPar);
            }
            else // Keep the GUID, but override the details
            {
                // If this Property has IfcGuid, use the IfdGuid set in the newPar, otherwise keep the original one
                if (!hasIfdGuid)
                {
                    newPar.ParamGuid = SharedParamFileDict[newPar.Name].ParamGuid;
                }
                SharedParamFileDict[newPar.Name] = newPar; // override the Dict
            }

            SharedParameterDef newParType = (SharedParameterDef)newPar.Clone();
            newParType.Name = newParType.Name + "[Type]";
            if (!SharedParamFileTypeDict.ContainsKey(newParType.Name))
            {
                SharedParamFileTypeDict.Add(newParType.Name, newParType);
            }
            else // Keep the GUID, but override the details
            {
                newParType.ParamGuid = SharedParamFileTypeDict[newParType.Name].ParamGuid;
                SharedParamFileTypeDict[newParType.Name] = newParType; // override the Dict
            }

            if (prop.NameAliases != null)
            {
                foreach (NameAlias alias in prop.NameAliases)
                {
                    LanguageType lang = checkAliasLanguage(alias.lang);
                    outF.WriteLine("\t\t\t\tifcPSE.AddLocalizedParameterName(LanguageType.{0}, \"{1}\");", lang, alias.Alias);
                }
            }

            string calcName = "Revit.IFC.Export.Exporter.PropertySet.Calculators." + prop.Name + "Calculator";
            outF.WriteLine("\t\t\t\tcalcType = System.Reflection.Assembly.GetExecutingAssembly().GetType(\"" + calcName + "\");");
            outF.WriteLine("\t\t\t\tif (calcType != null)");
            outF.WriteLine("\t\t\t\t\tifcPSE.PropertyCalculator = (PropertyCalculator) calcType.GetConstructor(Type.EmptyTypes).Invoke(new object[]{});");
            outF.WriteLine("\t\t\t\t{0}.AddEntry(ifcPSE);", varName);
            outF.WriteLine("");
        }
        private PsetDefinition ProcessPsetDef(string schemaVersion, FileInfo PSDfileName)
        {
            PsetDefinition pset = new PsetDefinition();
            XDocument      doc  = XDocument.Load(PSDfileName.FullName);

            // Older versions of psd uses namespace!
            var        nsInfo = doc.Root.Attributes("xmlns").FirstOrDefault();
            XNamespace ns     = "";

            if (nsInfo != null)
            {
                ns = nsInfo.Value;
            }

            pset.Name       = doc.Elements(ns + "PropertySetDef").Elements(ns + "Name").FirstOrDefault().Value;
            pset.IfcVersion = doc.Elements(ns + "PropertySetDef").Elements(ns + "IfcVersion").FirstOrDefault().Attribute("version").Value.Replace(" ", "");
            if (pset.IfcVersion.StartsWith("2"))
            {
                if (pset.IfcVersion.Equals("2X", StringComparison.CurrentCultureIgnoreCase))
                {
                    pset.IfcVersion = "IFC" + pset.IfcVersion.ToUpper() + "2"; // BUG in the documentation. It ony contains "2x" instead of "2x2"
                }
                else
                {
                    pset.IfcVersion = "IFC" + pset.IfcVersion.ToUpper(); // Namespace cannot start with a number. e.g. make sure 2x3 -> IFC2x3
                }
            }
            else if (pset.IfcVersion.StartsWith("IFC4"))
            {
                pset.IfcVersion = schemaVersion.ToUpper();
            }

            if (doc.Element(ns + "PropertySetDef").Attribute("ifdguid") != null)
            {
                pset.IfdGuid = doc.Element(ns + "PropertySetDef").Attribute("ifdguid").Value;
            }
            // Get applicable classes
            IEnumerable <XElement> applicableClasses = from el in doc.Descendants(ns + "ClassName") select el;
            IList <string>         applClassesList   = new List <string>();

            foreach (XElement applClass in applicableClasses)
            {
                applClassesList.Add(removeInvalidNName(applClass.Value));
            }
            pset.ApplicableClasses = applClassesList;

            IList <PsetProperty> propList = new List <PsetProperty>();
            var pDefs = from p in doc.Descendants(ns + "PropertyDef") select p;

            foreach (XElement pDef in pDefs)
            {
                PsetProperty prop = getPropertyDef(ns, pDef);
                if (prop == null)
                {
#if DEBUG
                    logF.WriteLine("%Error: Mising PropertyType data for {0}.{1}", pset.Name, pDef.Element(ns + "Name").Value);
#endif
                }
                else
                {
                    propList.Add(prop);
                }
            }
            pset.properties = propList;

            return(pset);
        }