Configure blockstack:  find and store configuration parameters to the config file.

   Optionally prompt for missing data interactively (with interactive=True).  Or, raise an exception
   if there are any fields missing.

   Optionally force a re-prompting for all configuration details (with force=True)

   Return {'blockstack': {...}, 'bitcoind': {...}, 'blockstack-api': {...}}

def configure(working_dir, config_file=None, force=False, interactive=False):
   """
   Configure blockstack:  find and store configuration parameters to the config file.

   Optionally prompt for missing data interactively (with interactive=True).  Or, raise an exception
   if there are any fields missing.

   Optionally force a re-prompting for all configuration details (with force=True)

   Return {'blockstack': {...}, 'bitcoind': {...}, 'blockstack-api': {...}}
   """

   if config_file is None:
      # get input for everything
      config_file = virtualchain.get_config_filename(get_default_virtualchain_impl(), working_dir)

   if not os.path.exists( config_file ):
       # definitely ask for everything
       force = True

   log.debug("Load config from '%s'" % config_file)

   # get blockstack opts
   blockstack_opts = {}
   blockstack_opts_defaults = default_blockstack_opts(working_dir, config_file=config_file)
   blockstack_params = blockstack_opts_defaults.keys()

   if not force or not interactive:
       # default blockstack options
       blockstack_opts = default_blockstack_opts(working_dir, config_file=config_file )

   blockstack_msg = "Please enter blockstack configuration hints."

   blockstack_opts, missing_blockstack_opts, num_blockstack_opts_prompted = find_missing( blockstack_msg, \
                                                                                          blockstack_params, \
                                                                                          blockstack_opts, \
                                                                                          blockstack_opts_defaults, \
                                                                                          prompt_missing=interactive )

   blockstack_api_opts = {}
   blockstack_api_defaults = default_blockstack_api_opts(working_dir, config_file=config_file)
   blockstack_api_params = blockstack_api_defaults.keys()
   
   if not force or not interactive:
       # default blockstack API options
       blockstack_api_opts = default_blockstack_api_opts(working_dir, config_file=config_file)

   blockstack_api_msg = "Please enter blockstack RESTful API configuration hints."

   blockstack_api_opts, missing_blockstack_api_opts, num_blockstack_api_opts_prompted = find_missing( blockstack_api_msg, \
                                                                                                      blockstack_api_params, \
                                                                                                      blockstack_api_opts, \
                                                                                                      blockstack_api_defaults, \
                                                                                                      prompt_missing=interactive )

   bitcoind_message  = "Blockstack does not have enough information to connect\n"
   bitcoind_message += "to bitcoind.  Please supply the following parameters, or\n"
   bitcoind_message += "press [ENTER] to select the default value."

   bitcoind_opts = {}
   bitcoind_opts_defaults = default_bitcoind_opts( config_file=config_file )
   bitcoind_params = bitcoind_opts_defaults.keys()

   if not force or not interactive:
      # get default set of bitcoind opts
      bitcoind_opts = default_bitcoind_opts( config_file=config_file )


   # get any missing bitcoind fields
   bitcoind_opts, missing_bitcoin_opts, num_bitcoind_prompted = find_missing( bitcoind_message, \
                                                                              bitcoind_params, \
                                                                              bitcoind_opts, \
                                                                              bitcoind_opts_defaults, \
                                                                              prompt_missing=interactive )

   if not interactive and (len(missing_bitcoin_opts) > 0 or len(missing_blockstack_opts) > 0 or len(missing_blockstack_api_opts) > 0):
       # cannot continue
       raise Exception("Missing configuration fields: %s" % (",".join( missing_blockstack_opts + missing_bitcoin_opts + missing_blockstack_api_opts )) )

   ret = {
      'blockstack': blockstack_opts,
      'bitcoind': bitcoind_opts,
      'blockstack-api': blockstack_api_opts
   }

   # if we prompted, then save
   if num_bitcoind_prompted > 0 or num_blockstack_opts_prompted > 0 or num_blockstack_api_opts_prompted > 0 or \
      (not os.path.exists(config_file) and not interactive):
       print >> sys.stderr, "Saving configuration to %s" % config_file
   
       # always set version when writing
       config_opts = copy.deepcopy(ret)
       if not config_opts['blockstack'].has_key('server_version'):
           config_opts['blockstack']['server_version'] = VERSION

       if not config_opts['blockstack-api'].has_key('server_version'):
           config_opts['blockstack']['server_version'] = VERSION

       # if the config file doesn't exist, then set the version 
       # in ret as well, since it's what's written
       if not os.path.exists(config_file):
           ret['blockstack']['server_version'] = VERSION
           ret['blockstack-api']['server_version'] = VERSION

       write_config_file( config_opts, config_file )

   # prefix our bitcoind options, so they work with virtualchain
   ret['bitcoind'] = opt_restore("bitcoind_", ret['bitcoind'])
   return ret