#!/usr/bin/python
#coding=utf-8

__author__ = 'justin.bto@gmail.com (Justin Zhou)'

import os
import pickle
import collections
import sys
import webbrowser


from adspygoogle.common import SanityCheck
from adspygoogle.common.Errors import InvalidInputError
from adspygoogle.common.Logger import Logger
from oauth2client import client



HOME = os.path.expanduser('~')
AUTH_PKL = os.path.join(HOME, 'dfa_api_auth.pkl')
CONFIG_PKL = os.path.join(HOME, 'dfa_api_config.pkl')
LOG_HOME = os.path.join(HOME, 'logs')
LOG_NAME = 'dfa_api_lib'

PRODUCT_TO_OAUTH_SCOPE = collections.OrderedDict([
    ('AdWords / Ad Exchange Buyer', 'https://adwords.google.com/api/adwords'),
    ('DoubleClick for Advertisers',
     'https://www.googleapis.com/auth/dfatrafficking'),
    ('DoubleClick for Publishers', 'https://www.google.com/apis/ads/publisher')
])

def ChooseProduct():
  """Prompt the user to choose which product they want a refresh token for.

  Returns:
    str The product the user chose. Will always be one of the keys from the
    PRODUCT_TO_OAUTH_SCOPE dictionary.
  """
  potential_products = PRODUCT_TO_OAUTH_SCOPE.keys()
  while True:
    print 'Please choose which product you want to use:'
    for index, product in enumerate(potential_products):
      print '\t%s) %s' % (index + 1, product)
    choice = raw_input('Please enter a number: ').strip()
    try:
      choice = int(choice) - 1
    except ValueError:
      print 'Invalid choice.'
      continue
    if 0 <= (choice) < len(potential_products):
      return potential_products[choice]
    print 'Invalid choice.'

def GenerateRefreshToken():
  """Prompt the user for information to generate and output a refresh token."""
  print ('Please enter your OAuth 2.0 Client ID and Client Secret.\n'
         'These values can be generated from the Google APIs Console, '
         'https://code.google.com/apis/console under the API Access tab.\n'
         'Please use a Client ID for installed applications.')
  client_id = '800523524577.apps.googleusercontent.com'
  client_secret = '4AoEFfQChNlQOuY4H6MRcsHE'
  product = ChooseProduct()

  flow = client.OAuth2WebServerFlow(
      client_id=client_id,
      client_secret=client_secret,
      scope=PRODUCT_TO_OAUTH_SCOPE[product],
      user_agent='Ads Python Client Library',
      redirect_uri='urn:ietf:wg:oauth:2.0:oob')

  authorize_url = flow.step1_get_authorize_url()

  print ('Log into the Google Account you use to access your %s account and go '
         'to the following URL: \n%s\n' % (product, authorize_url))
  webbrowser.open_new_tab(authorize_url)
  print 'After approving the token enter the verification code (if specified).'
  code = raw_input('Code: ').strip()

  try:
    credential = flow.step2_exchange(code)
  except client.FlowExchangeError, e:
    print 'Authentication has failed: %s' % e
    sys.exit(1)
  else:
    print ('OAuth 2.0 authorization successful!\n\n'
           'Your refresh token is: %s' % credential.refresh_token)
    return credential.refresh_token

def main():
    logger = Logger(os.path.join(LOG_HOME))

    #获取新的token
    refresh_token = GenerateRefreshToken()
    
    # Load existing authentication credentials from dfa_api_auth.pkl.
    old_auth = {}
    if os.path.exists(AUTH_PKL):
            try:
                    fh = open(AUTH_PKL, 'r')
                    try:
                            old_auth = pickle.load(fh)
                    finally:
                            fh.close()
            except IOError, e:
                    logger.Log(LOG_NAME, e, log_level=Logger.ERROR)

    # Prompt user for authentication and configuration values.
    print """
    --~--~---------~--~----~------------~-------~--~----~
    All requests to the non-LoginService that are sent to
    the DFA API web services must include SOAP header
    elements. Currently accepted header elements are
    Username and OAuth 2.0 access token. We use clientId,
    clientSecret, and refreshToken to enable this feature.

    To overwrite an existing header element, explicitly
    type new value (or 'none' to clear) at the prompt.
    The default behavior is to keep old values.
    -~----------~----~----~----~------~----~------~--~---\n"""
    prompts = (('Your DFA account\'s username', 'Username',
                'auth'),
               ('OAuth 2.0 client ID (retrieved from '
                'code.google.com/apis/console under the API Access tab)',
                'clientId', 'auth'),
               ('OAuth 2.0 client secret (retrieved from '
                'code.google.com/apis/console under the API Access tab)',
                'clientSecret', 'auth'),
               ('OAuth 2.0 refresh token (if you don\'t already have one, run '
                'scripts/common/generate_refresh_token.py', 'refreshToken', 'auth'),
               ('Select XML parser [1=PyXML (recommended), 2=ElementTree]',
                'xml_parser', 'config'),
               ('Enable debugging mode', 'debug', 'config'),
               ('Enable SOAP XML logging mode', 'xml_log', 'config'),
               ('Enable API request logging mode', 'request_log', 'config'),
               ('Enter an application name', 'app_name', 'config'))
    auth = {}
    config = {
        'home': HOME,
        'log_home': LOG_HOME
    }
    for prompt_msg, header, source in prompts:
            if source == 'auth':
                    # Construct prompt message.
                    try:
                            prompt_msg = '%s [%s]: ' % (prompt_msg, old_auth[header])
                    except (NameError, KeyError), e:
                            prompt_msg = '%s: ' % prompt_msg

                    # Prompt user to keep/update authentication credentials.
                    auth[header] = raw_input(prompt_msg).rstrip('\r')
                    if header in old_auth:
                            if auth[header] == 'none':
                                    auth[header] = ''
                            elif not auth[header]:
                                    auth[header] = old_auth[header]
                    else:
                            if auth[header] == 'none':
                                    auth[header] = ''
            elif source == 'config':
                    # Prompt user to update configuration values.
                    if header == 'xml_parser':
                            res = raw_input('%s: ' % prompt_msg).rstrip('\r')
                            if not SanityCheck.IsConfigUserInputValid(res, ['1', '2']):
                                    msg = 'Possible values are \'1\' or \'2\'.'
                                    raise InvalidInputError(msg)
                    elif header == 'app_name':
                            res = raw_input('%s: ' % prompt_msg).rstrip('\r')
                    else:
                            res = raw_input('%s [y/n]: ' % prompt_msg).rstrip('\r')
                            if not SanityCheck.IsConfigUserInputValid(res, ['y', 'n']):
                                    msg = 'Possible values are \'y\' or \'n\'.'
                                    raise InvalidInputError(msg)
                    config[header] = res

    # Load new authentication credentials into dfa_api_auth.pkl.
    try:
            fh = open(AUTH_PKL, 'w')
            try:
                    pickle.dump(auth, fh)
            finally:
                    fh.close()
    except IOError, e:
            logger.Log(LOG_NAME, e, log_level=Logger.ERROR)

    # Load new configuratation values into dfa_api_config.pkl.
    try:
            fh = open(CONFIG_PKL, 'w')
            try:
                    pickle.dump(config, fh)
            finally:
                    fh.close()
    except IOError, e:
            logger.Log(LOG_NAME, e, log_level=Logger.ERROR)

if __name__ == '__main__':
  main()
