"""
==============================================
Extend login Interface for fogbugz
Parts of this code comes from the fborm project
==============================================
"""

from __future__ import print_function
import getpass
import contextlib
import os
import re

try:
    # For Python 3.0 and later
    from urllib.request import urlopen
except ImportError:
    # Fall back to Python 2's urllib2
    from urllib2 import urlopen

__version__ = (0,3,0)
__version_string__ = '.'.join(str(x) for x in __version__)

__author__ = 'Nicolas Morales'
__email__ = 'portu.github@gmail.com'

def get_input(prompt):
    '''Wrapper around builtin function raw_input in order to mock it in tests'''
    return raw_input(prompt)

def get_credentials(fogbugzrc=None, fogbugzPrefix='', interactive=True):
    """When credentials are not provided in the constructor, get them from fogbugzrc or prompt user
       fogbugzrc: Path to fogbugzrc file
       fogbugzPrefix: prefix for user and password. Useful if the fogbugzrc is used for multiple servers
                 with different credentials
       interactive: If credentials not found in fogbugzrc and this is set, prompt the user
    """
    #Search whether there is an fogbugzrc file. Default: ~/fogbugzrc
    username = None
    password = None
    if not fogbugzrc:
        fogbugzrc = os.path.join(os.path.expanduser("~"), '.fogbugzrc')
    if os.path.isfile(fogbugzrc):
        for line in open(fogbugzrc):
            line = line.split('#')[0]
            if fogbugzPrefix + 'username' in line:
                res = re.search(r'username\s*=\s*(\S+)', line)
                username = res.group(1)
            elif fogbugzPrefix + 'password' in line:
                res = re.search(r'password\s*=\s*(\S+)', line)
                password = res.group(1)
    if interactive:
        if not username:
            username = get_input('user: ')
        if not password:
            password = getpass.getpass('password: ')# Same as raw_input but hide what user types
    return username, password

def get_token(fogbugzrc=None, fogbugzPrefix=''):
    """When token is not provided in the constructor, get them from fogbugzrc
       fogbugzrc: Path to fogbugzrc file
       fogbugzPrefix: prefix for token.
    """
    # Search whether there is an fogbugzrc file. Default: ~/.fogbugzrc
    token = None
    if not fogbugzrc:
        fogbugzrc = os.path.join(os.path.expanduser("~"), '.fogbugzrc')
    if os.path.isfile(fogbugzrc):
        for line in open(fogbugzrc):
            line = line.split('#')[0]
            if fogbugzPrefix + 'token' in line:
                res = re.search(r'token\s*=\s*(\S+)', line)
                token = res.group(1)
    return token

def validate_token(hostname, token):
    """
    Validate the user token.

    Returns True for a successful validation.
    """
    url = hostname + "/api.asp?cmd=logon&token=" + token
    try:
        response = urlopen(url)
        return token in response.read()
    except Exception as e:
        print(e)
    return False

def FogBugz(fbConstructor, hostname, token=None, username=None, password=None, fogbugzrc=None,
            fogbugzPrefix='', interactive=True, storeCredentials=False):
    """Calls the constructor specified by fbConstructor (hence, despite this being a function use
        CapWords naming convention)

       fbConstructor: Fogbugz constructor class. Typically fogbugz.FogBugz, fborm.FogBugzORM or
                       kiln.Kiln
       hostname: passed directly to the fbInterface
       token, username, password: input credentials
       fogbugzrc, fogbugzPrefix, interactive: Passed to method get_credentials
       storeCredentials: If active, create attributes token, username and password. This opens the
                          door to using it for login to other system, which is convenient, but the
                          programmer can also do what he wants with the password (which is bad).
       TODO: Support passing a list of args to fbConstructor
    """
    if token and (username or password):
        raise TypeError("If you supply 'token' you cannot supply 'username' or 'password'")
    if (username and not password) or (not username and password):
        raise TypeError("You must supply both 'username' and 'password'")
    if not username:
        if not token:
            token = get_token(fogbugzrc, fogbugzPrefix)
        if token and validate_token(hostname, token):
            return fbConstructor(hostname, token=token)
        else:
            username, password = get_credentials(fogbugzrc, fogbugzPrefix, interactive)
            if not username and password: # If still no credentials available, raise
                raise TypeError("You must provide either 'username' and 'password' or 'token'")

    fb = fbConstructor(hostname, token=token)
    if username:
        fb.logon(username, password)

    if storeCredentials:
        fb.token = token
        fb.username = username
        fb.password = password

    return fb

@contextlib.contextmanager
def FogBugz_cm(fbConstructor, hostname, logoff=False, **kwargs):
    '''Context manager with logOff functionality'''
    fb = FogBugz(fbConstructor, hostname, **kwargs)
    yield fb

    if logoff:
        fb.logoff()

@@ -798,24 +798,25 @@
 ue):%0A    %22%22%22
+ 
 When credent
@@ -895,32 +895,33 @@
 mpt user%0A       
+ 
 fogbugzrc: Path 
@@ -930,32 +930,33 @@
  fogbugzrc file%0A
+ 
        fogbugzPr
@@ -1084,24 +1084,25 @@
 credentials%0A
+ 
        inter
@@ -2107,16 +2107,17 @@
 %0A    %22%22%22
+ 
 When tok
@@ -2178,32 +2178,33 @@
 ogbugzrc%0A       
+ 
 fogbugzrc: Path 
@@ -2217,24 +2217,25 @@
 bugzrc file%0A
+ 
        fogbu
@@ -2768,20 +2768,16 @@
 %0A    %22%22%22
-%0A   
  Validat
@@ -2795,16 +2795,20 @@
 token.%0A%0A
+    
     Retu
@@ -3228,16 +3228,17 @@
 %0A    %22%22%22
+ 
 Calls th
@@ -3364,16 +3364,17 @@
 %0A       
+ 
 fbConstr
@@ -3487,16 +3487,17 @@
 ln.Kiln%0A
+ 
        h
@@ -3543,24 +3543,25 @@
 face%0A       
+ 
 token, usern
@@ -3589,24 +3589,25 @@
 credentials%0A
+ 
        fogbu
@@ -3669,24 +3669,25 @@
 credentials%0A
+ 
        store
@@ -3976,16 +3976,17 @@
 %0A       
+ 
 TODO: Su
@@ -5134,16 +5134,17 @@
 %0A    '''
+ 
 Context 

Change to docstring format