from colorama import Fore, Style
from orcid import PublicAPI

__author__ = 'cwilli34'


class OrcidSearchResults:

    """Using the Orcid Public API."""

    def __init__(self, sandbox=True):
        """Initialize public API for class.

        Parameters
        ----------
        :param sandbox: boolean
            Should the sandbox be used. True (default) indicates development mode.
        """
        self.api = PublicAPI(sandbox=sandbox)
        self.s_dict = dict()
        self.orcid_id = []
        self.total_results = 0
        self.actual_total_results = 0

    def basic_search(self, query):
        """Basic search based on search terms entered by user to find an Orcid ID.

        Parameters
        ----------
        :param query: string
            A phrase, or group of search terms with boolean operators for lucene search

        Returns
        -------
        :returns self.s_dict: dict type
            Records with minimal information based on search terms used.
        """
        search_results = self.api.search_public(query, start=0, rows=100)
        results = search_results.get('orcid-search-results', None)
        self.actual_total_results = results.get('num-found', 0)
        result = results.get('orcid-search-result', None)

        # Actual results versus displayed results
        if self.actual_total_results > 99:
            self.total_results = 100
        else:
            self.total_results = self.actual_total_results

        # Only last name, first name, Orcid ID, and email will be displayed for each record
        for p in range(self.total_results):
            try:
                f_name = result[p]['orcid-profile']['orcid-bio']['personal-details']['given-names']['value']
            except TypeError:
                pass
            try:
                l_name = result[p]['orcid-profile']['orcid-bio']['personal-details']['family-name']['value']
            except TypeError:
                pass
            try:
                contact_details = result[p]['orcid-profile']['orcid-bio'].get('contact-details', None)
            except AttributeError:
                pass

            if contact_details is None:
                self.s_dict.update(
                    {
                        result[p]['orcid-profile']['orcid-identifier']['path']:
                            {
                                'f_name': f_name,
                                'l_name': l_name
                            }
                    }
                )
            else:
                email = contact_details.get('email', None)

                if email is None or email == []:
                    self.s_dict.update(
                        {
                            result[p]['orcid-profile']['orcid-identifier']['path']:
                                {
                                    'f_name': f_name,
                                    'l_name': l_name
                                }
                        }
                    )
                else:
                    l = dict()
                    for k, e in enumerate(email):
                        c = e.get('value')
                        l[k + 1] = c

                    self.s_dict.update(
                        {
                            result[p]['orcid-profile']['orcid-identifier']['path']:
                                {
                                    'f_name': f_name,
                                    'l_name': l_name,
                                    'email': l
                                }
                        }
                    )

        # To just get a list of Orcid ID's without any other profile information
        self.orcid_id = self.s_dict.keys()

        return self.s_dict

        # For testing ###
        # results = self.api.search_public(query)
        # pp(results)

    def advanced_search(self, query, record_type=None, put_code=None):
        """Advance search once the Orcid ID is known.  Can find more detailed record information with
            Orcid ID, record type and put codes.

        Parameters
        ----------
        :param query: string
            Id of the queried author.
        :param record_type: string
            One of 'activities', 'education', 'employment', 'funding',
            'peer-review', 'work'. 'activities' is more of a summary.
        :param put_code: string
            The id of the queried work. Must be given if 'request_type' is not
            'activities'.

        Returns
        -------
        :returns: summary, dict type
            summary of user records.
        :returns: education, dict type
            user's education record.
        :returns: employment, dict type
            user's employment record.
        :returns: funding, dict type
            user's funding record.
        :returns: peer_review, dict type
            user's peer review record.
        :returns: work, dict type
            user's research works and publications.
        """
        if put_code and record_type:
            if record_type == 'education':
                education = self.api.read_record_public(query, record_type, put_code)
                return education
            elif record_type == 'employment':
                employment = self.api.read_record_public(query, record_type, put_code)
                return employment
            elif record_type == 'funding':
                funding = self.api.read_record_public(query, record_type, put_code)
                return funding
            elif record_type == 'peer-review':
                peer_review = self.api.read_record_public(query, record_type, put_code)
                return peer_review
            elif record_type == 'work':
                work = self.api.read_record_public(query, record_type, put_code)
                return work

        summary = self.api.read_record_public(query, 'activities')
        return summary

    def print_basic(self):
        """Print basic search results for better user readability.

        Parameters
        ----------
        :param: None

        Returns
        -------
        :returns: None
        """
        result_text = \
            Fore.YELLOW + \
            Style.BRIGHT + \
            "Search Results: " + \
            Fore.RESET + \
            '(' + \
            str(self.total_results) + \
            ' Total)' + \
            Style.RESET_ALL
        result_warning_text = \
            Fore.RED + Style.BRIGHT + \
            "You have a lot of results!!\n" + \
            Fore.RESET + \
            "Please modify or add more search terms to narrow your results.\n" + \
            Style.RESET_ALL

        print(result_text + '\n')
        if self.total_results > 30:
            print(result_warning_text)

        for i, p in enumerate(self.s_dict):
            email = self.s_dict[p].get('email')
            l_name = self.s_dict[p].get('l_name')
            f_name = self.s_dict[p].get('f_name')

            id_text = Fore.BLUE + '{0:14}{1:40}'.format('Orcid ID:', Fore.RESET + p)
            l_name_text = Fore.BLUE + '{0:14}{1:40}'.format('Last Name:', Fore.RESET + l_name)
            f_name_text = Fore.BLUE + '{0:14}{1:40}'.format('First Name:',  Fore.RESET + f_name)
            email_text = Fore.BLUE + 'Email:' + Fore.RESET
            count = \
                Fore.MAGENTA + \
                Style.BRIGHT + \
                '{0:14}{1:40}'.format(
                    'Result:',
                    Fore.RESET +
                    Fore.YELLOW +
                    str(i + 1) +
                    Fore.RESET+ \
                    Style.RESET_ALL
                )

            print(count)
            print(id_text)
            print(l_name_text)
            print(f_name_text)

            if email is not None:
                for e in email:
                    email_address_text = email[e]
                    if e == 1:
                        print('{0:24}'.format(email_text) + '{0:40}'.format(email_address_text))
                    else:
                        print('{0:14}'.format("") + '{0:40}'.format(email_address_text))

            print("" + Style.RESET_ALL)

    def print_basic_alt(self):
        """Print basic search results for better user readability (Alternative Format).

        Parameters
        ----------
        :param: None

        Returns
        -------
        :returns: None
        """
        result_text = \
            Fore.YELLOW + \
            Style.BRIGHT + \
            "Search Results: " + \
            Fore.RESET + \
            '(' + \
            str(self.total_results) + \
            ' Total)' + \
            Style.RESET_ALL
        result_warning_text = \
            Fore.RED + \
            Style.BRIGHT + \
            "You have a lot of results!!\n" + \
            Fore.RESET + \
            "Please modify or add more search terms to narrow your results.\n" + \
            Style.RESET_ALL

        print(result_text + '\n')
        if self.total_results > 30:
            print(result_warning_text)

        for i, p in enumerate(self.s_dict):
            email = self.s_dict[p].get('email')
            l_name = self.s_dict[p].get('l_name')
            f_name = self.s_dict[p].get('f_name')

            id_text = p
            l_name_text = l_name
            f_name_text = f_name
            count = \
                Fore.MAGENTA + \
                Style.BRIGHT + \
                'Result: ' + \
                Fore.RESET + \
                Fore.YELLOW + \
                str(i + 1) + \
                Fore.RESET + \
                Style.RESET_ALL

            email_list = []

            if email is not None:
                for e in email:
                    email_list.insert(e, email[e])

            print(count +
                  ', ' +
                  id_text +
                  ', ' +
                  f_name_text +
                  ' ' +
                  l_name_text +
                  (' (' if email_list else '') +
                  ', '.join(email_list) +
                  (') ' if email_list else ''))
        print("" + Style.RESET_ALL)

    # Possible to create advance printing dialogs so less code is required in the calling program
    # def print_advance(self):
