/***************************************************/
        /****              Public methods               ****/
        /***************************************************/

        public static Definition ProjectParameter(Document document, string parameterName, ParameterType parameterType, BuiltInParameterGroup parameterGroup, bool instance, IEnumerable <Category> categories)
        {
            // Inspired by https://github.com/DynamoDS/DynamoRevit/blob/master/src/Libraries/RevitNodes/Elements/Parameter.cs

            if (categories != null && !categories.Any())
            {
                BH.Engine.Reflection.Compute.RecordError($"Parameter {parameterName} of type {LabelUtils.GetLabelFor(parameterType)} could not be created because no category bindings were provided.");
                return(null);
            }

            // Look for existing parameter definition
            bool bindings = false;
            IEnumerable <Definition> existingDefs = new FilteredElementCollector(document).OfClass(typeof(SharedParameterElement)).Cast <SharedParameterElement>().Select(x => x.GetDefinition());
            Definition def = existingDefs.FirstOrDefault(x => x.Name == parameterName && x.ParameterGroup == parameterGroup);

            if (def != null)
            {
                if (document.ParameterBindings.Contains(def))
                {
                    BH.Engine.Reflection.Compute.RecordWarning($"Parameter {parameterName} already exists in group {LabelUtils.GetLabelFor(parameterGroup)}. It already has category bindings, they were not updated - please make sure they are correct.");
                    bindings = true;
                }
                else
                {
                    BH.Engine.Reflection.Compute.RecordWarning($"Parameter {parameterName} already exists in group {LabelUtils.GetLabelFor(parameterGroup)}. It did not have any category bindings, so input bindings were applied.");
                }
            }
            else
            {
                // buffer the current shared parameter file name and apply a new empty parameter file instead
                string sharedParameterFile     = document.Application.SharedParametersFilename;
                string tempSharedParameterFile = System.IO.Path.GetTempFileName() + ".txt";
                using (System.IO.File.Create(tempSharedParameterFile)) { }
                document.Application.SharedParametersFilename = tempSharedParameterFile;

                // Create a new shared parameter, since the file is empty everything has to be created from scratch
                def = document.Application.OpenSharedParameterFile()
                      .Groups.Create("TempParameterGroup").Definitions.Create(
                    new ExternalDefinitionCreationOptions(parameterName, parameterType)) as ExternalDefinition;

                // apply old shared parameter file
                document.Application.SharedParametersFilename = sharedParameterFile;

                // delete temp shared parameter file
                System.IO.File.Delete(tempSharedParameterFile);
            }

            if (!bindings)
            {
                // Apply instance or type binding
                CategorySet paramCategories = (categories == null) ? document.CategoriesWithBoundParameters() : Create.CategorySet(document, categories);

                Binding bin = (instance) ?
                              (Binding)document.Application.Create.NewInstanceBinding(paramCategories) :
                              (Binding)document.Application.Create.NewTypeBinding(paramCategories);

                document.ParameterBindings.Insert(def, bin, parameterGroup);
            }

            return(def);
        }