/// <summary>
 ///
 /// </summary>
 /// <param name="id"></param>
 /// <param name="requestImpl">An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST</param>
 /// <returns></returns>
 public void CompleteFind(int id, RequestImpl requestImpl)
 {
     try {
         // create a strongly-typed request object.
         using (var request = requestImpl.As <Request>()) {
             // Nice-to-have put a debug message in that tells what's going on.
             request.Debug("Calling '{0}::CompleteFind' '{1}'", ProviderName, id);
         }
     }
     catch (Exception e) {
         // We shoudn't throw exceptions from here, it's not-optimal. And if the exception class wasn't properly Serializable, it'd cause other issues.
         // Really this is just here as a precautionary to behave correctly.
         // At the very least, we'll write it to the system debug channel, so a developer can find it if they are looking for it.
         Debug.WriteLine(string.Format("Unexpected Exception thrown in '{0}::CompleteFind' -- {1}\\{2}\r\n{3}"), ProviderName, e.GetType().Name, e.Message, e.StackTrace);
     }
 }
        /// <summary>
        /// Returns dynamic option definitions to the HOST
        /// </summary>
        /// <param name="category">The category of dynamic options that the HOST is interested in</param>
        /// <param name="requestImpl">An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST</param>
        public void GetDynamicOptions(string category, RequestImpl requestImpl)
        {
            try {
                // create a strongly-typed request object.
                using (var request = requestImpl.As <Request>()) {
                    // Nice-to-have put a debug message in that tells what's going on.
                    request.Debug("Calling '{0}::GetDynamicOptions' '{1}'", ProviderName, category);
                    OptionCategory cat;
                    if (!Enum.TryParse(category ?? "", true, out cat))
                    {
                        // unknown category
                        return;
                    }

                    switch (cat)
                    {
                    case OptionCategory.Install:
                        // options required for install/uninstall/getinstalledpackages
                        break;

                    case OptionCategory.Provider:
                        // options used with this provider. Not currently used.
                        break;

                    case OptionCategory.Source:
                        // options for package sources
                        request.YieldDynamicOption(cat, Constants.FavoriteColorParameter, OptionType.String, false);
                        request.YieldDynamicOption(cat, Constants.SkipValidationParameter, OptionType.Switch, false);
                        break;

                    case OptionCategory.Package:
                        // options used when searching for packages
                        break;
                    }
                }
            }
            catch (Exception e) {
                // We shoudn't throw exceptions from here, it's not-optimal. And if the exception class wasn't properly Serializable, it'd cause other issues.
                // Really this is just here as a precautionary to behave correctly.
                // At the very least, we'll write it to the system debug channel, so a developer can find it if they are looking for it.
                Debug.WriteLine(string.Format("Unexpected Exception thrown in '{0}::GetDynamicOptions' -- {1}\\{2}\r\n{3}"), ProviderName, e.GetType().Name, e.Message, e.StackTrace);
            }
        }
        /// <summary>
        /// Performs one-time initialization of the PROVIDER.
        /// </summary>
        /// <param name="dynamicInterface">a <c>System.Type</c> that represents a remote interface for that a request needs to implement when passing the request back to methods in the CORE. (Advanced Usage)</param>
        /// <param name="requestImpl">An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST</param>
        public void InitializeProvider(object dynamicInterface, RequestImpl requestImpl)
        {
            try {
                // this is used by the RequestExtensions to generate a remotable dynamic interface for cross-appdomain calls.
                // NOTE:leave this in, unless you really know what you're doing, and aren't going to use the strongly-typed request interface.
                RequestExtensions.RemoteDynamicInterface = dynamicInterface;

                // create a strongly-typed request object.
                using (var request = requestImpl.As <Request>()) {
                    // Nice-to-have put a debug message in that tells what's going on.
                    request.Debug("Calling '{0}::InitializeProvider'", ProviderName);

                    // todo: put any one-time initialization code here.
                }
            }
            catch (Exception e) {
                // We shoudn't throw exceptions from here, it's not-optimal. And if the exception class wasn't properly Serializable, it'd cause other issues.
                // Really this is just here as a precautionary to behave correctly.
                // At the very least, we'll write it to the system debug channel, so a developer can find it if they are looking for it.
                Debug.WriteLine(string.Format("Unexpected Exception thrown in '{0}::InitializeProvider' -- {1}\\{2}\r\n{3}"), ProviderName, e.GetType().Name, e.Message, e.StackTrace);
            }
        }
        /// <summary>
        /// This is called when the user is adding (or updating) a package source
        ///
        /// If this PROVIDER doesn't support user-defined package sources, remove this method.
        /// </summary>
        /// <param name="name">The name of the package source. If this parameter is null or empty the PROVIDER should use the location as the name (if the PROVIDER actually stores names of package sources)</param>
        /// <param name="location">The location (ie, directory, URL, etc) of the package source. If this is null or empty, the PROVIDER should use the name as the location (if valid)</param>
        /// <param name="trusted">A boolean indicating that the user trusts this package source. Packages returned from this source should be marked as 'trusted'</param>
        /// <param name="requestImpl">An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST</param>
        public void AddPackageSource(string name, string location, bool trusted, RequestImpl requestImpl)
        {
            try{
                // create a strongly-typed request object.
                using (var request = requestImpl.As <Request>()) {
                    // Nice-to-have put a debug message in that tells what's going on.
                    request.Debug("Calling '{0}::AddPackageSource' '{1}','{2}','{3}'", ProviderName, name, location, trusted);

                    // if they didn't pass in a name, use the location as a name. (if you support that kind of thing)
                    name = string.IsNullOrEmpty(name) ? location : name;

                    // let's make sure that they've given us everything we need.
                    if (string.IsNullOrEmpty(name))
                    {
                        request.Error(ErrorCategory.InvalidArgument, Constants.NameParameter, Constants.MissingRequiredParameter, Constants.NameParameter);
                        // we're done here.
                        return;
                    }

                    if (string.IsNullOrEmpty(location))
                    {
                        request.Error(ErrorCategory.InvalidArgument, Constants.LocationParameter, Constants.MissingRequiredParameter, Constants.LocationParameter);
                        // we're done here.
                        return;
                    }

                    // if this is supposed to be an update, there will be a dynamic parameter set for IsUpdatePackageSource
                    var isUpdate = request.GetOptionValue(OptionCategory.Source, Constants.IsUpdateParameter).IsTrue();

                    // if your source supports credentials you get get them too:
                    // string username =request.Username;
                    // SecureString password = request.Password;
                    // feel free to send back an error here if your provider requires credentials for package sources.

#if !NEED_FAVORITE_COLOR
                    // if you have dynamic parameters that you declared, you can retrieve their values too.
                    // this sort of thing is only needed for additional parameters outside of name, location, credentials, and istrusted.
                    var favoriteColor = request.GetOptionValue(OptionCategory.Source, Constants.FavoriteColorParameter);

                    if (string.IsNullOrEmpty(favoriteColor))
                    {
                        // send an error
                        request.Error(ErrorCategory.InvalidArgument, Constants.FavoriteColorParameter, Constants.MissingRequiredParameter, Constants.FavoriteColorParameter);
                        // we're done here.
                        return;
                    }
#endif

                    // check first that we're not clobbering an existing source, unless this is an update

                    // todo: insert code to look up package source (from whereever you store it)

                    if (ExampleFoundExistingSource && !isUpdate)
                    {
                        // tell the user that there's one here already
                        request.Error(ErrorCategory.InvalidArgument, name ?? location, Constants.PackageProviderExists, name ?? location);
                        // we're done here.
                        return;
                    }

                    // conversely, if it didn't find one, and it is an update, that's bad too:
                    if (!ExampleFoundExistingSource && isUpdate)
                    {
                        // you can't find that package source? Tell that to the user
                        request.Error(ErrorCategory.ObjectNotFound, name ?? location, Constants.UnableToResolveSource, name ?? location);
                        // we're done here.
                        return;
                    }

                    // ok, we know that we're ok to save this source
                    // next we check if the location is valid (if we support that kind of thing)

                    var validated = false;
#if !SUPPORTS_PACKAGE_SOURCE_VALIDATION
                    if (!request.GetOptionValue(OptionCategory.Source, Constants.SkipValidationParameter).IsTrue())
                    {
                        // the user has not opted to skip validating the package source location, so check that it's valid (talk to the url, or check if it's a valid directory, etc)
                        // todo: insert code to check if the source is valid

                        if (ExamplePackageSourceIsNotValid)
                        {
                            request.Error(ErrorCategory.InvalidData, name ?? location, Constants.SourceLocationNotValid, location);
                            // we're done here.
                            return;
                        }

                        // we passed validation!
                        validated = true;
                    }
#endif

                    // it's good to check just before you actaully write something to see if the user has cancelled the operation
                    if (request.IsCancelled())
                    {
                        return;
                    }

                    // looking good -- store the package source
                    // todo: create the package source (and store it whereever you store it)

                    request.Verbose("Storing package source {0}", name);

                    // and, before you go, Yield the package source back to the caller.

                    if (!request.YieldPackageSource(name, location, trusted, true /*since we just registered it*/, validated))
                    {
                        // always check the return value of a yield, since if it returns false, you don't keep returning data
                        // this can happen if they have cancelled the operation.
                        return;
                    }

#if !NEED_FAVORITE_COLOR
                    // if you have additional parameters that are associated with the source
                    // you can return that data too if you'd like.
                    if (!request.YieldKeyValuePair(Constants.FavoriteColorParameter, favoriteColor))
                    {
                        // always check the return value of a yield, since if it returns false, you don't keep returning data
                        return;
                    }
#endif
                    // all done!
                }
            } catch (Exception e) {
                // We shoudn't throw exceptions from here, it's not-optimal. And if the exception class wasn't properly Serializable, it'd cause other issues.
                // Really this is just here as a precautionary to behave correctly.
                // At the very least, we'll write it to the system debug channel, so a developer can find it if they are looking for it.
                Debug.WriteLine(string.Format("Unexpected Exception thrown in {0} PackageProvider -- {1}\\{2}\r\n{3}"), ProviderName, e.GetType().Name, e.Message, e.StackTrace);
            }
        }